bevy_ecs/component/
info.rs

1use alloc::{borrow::Cow, vec::Vec};
2use bevy_platform::{hash::FixedHasher, sync::PoisonError};
3use bevy_ptr::OwningPtr;
4#[cfg(feature = "bevy_reflect")]
5use bevy_reflect::Reflect;
6use bevy_utils::{prelude::DebugName, TypeIdMap};
7use core::{
8    alloc::Layout,
9    any::{Any, TypeId},
10    fmt::Debug,
11    mem::needs_drop,
12};
13use indexmap::IndexSet;
14
15use crate::{
16    archetype::ArchetypeFlags,
17    component::{
18        Component, ComponentCloneBehavior, ComponentMutability, QueuedComponents,
19        RequiredComponents, StorageType,
20    },
21    lifecycle::ComponentHooks,
22    query::DebugCheckedUnwrap as _,
23    relationship::RelationshipAccessor,
24    resource::Resource,
25    storage::SparseSetIndex,
26};
27
28/// Stores metadata for a type of component or resource stored in a specific [`World`](crate::world::World).
29#[derive(Debug, Clone)]
30pub struct ComponentInfo {
31    pub(super) id: ComponentId,
32    pub(super) descriptor: ComponentDescriptor,
33    pub(super) hooks: ComponentHooks,
34    pub(super) required_components: RequiredComponents,
35    /// The set of components that require this components.
36    /// Invariant: components in this set always appear after the components that they require.
37    pub(super) required_by: IndexSet<ComponentId, FixedHasher>,
38}
39
40impl ComponentInfo {
41    /// Returns a value uniquely identifying the current component.
42    #[inline]
43    pub fn id(&self) -> ComponentId {
44        self.id
45    }
46
47    /// Returns the name of the current component.
48    #[inline]
49    pub fn name(&self) -> DebugName {
50        self.descriptor.name.clone()
51    }
52
53    /// Returns `true` if the current component is mutable.
54    #[inline]
55    pub fn mutable(&self) -> bool {
56        self.descriptor.mutable
57    }
58
59    /// Returns [`ComponentCloneBehavior`] of the current component.
60    #[inline]
61    pub fn clone_behavior(&self) -> &ComponentCloneBehavior {
62        &self.descriptor.clone_behavior
63    }
64
65    /// Returns the [`TypeId`] of the underlying component type.
66    /// Returns `None` if the component does not correspond to a Rust type.
67    #[inline]
68    pub fn type_id(&self) -> Option<TypeId> {
69        self.descriptor.type_id
70    }
71
72    /// Returns the layout used to store values of this component in memory.
73    #[inline]
74    pub fn layout(&self) -> Layout {
75        self.descriptor.layout
76    }
77
78    #[inline]
79    /// Get the function which should be called to clean up values of
80    /// the underlying component type. This maps to the
81    /// [`Drop`] implementation for 'normal' Rust components
82    ///
83    /// Returns `None` if values of the underlying component type don't
84    /// need to be dropped, e.g. as reported by [`needs_drop`].
85    pub fn drop(&self) -> Option<unsafe fn(OwningPtr<'_>)> {
86        self.descriptor.drop
87    }
88
89    /// Returns a value indicating the storage strategy for the current component.
90    #[inline]
91    pub fn storage_type(&self) -> StorageType {
92        self.descriptor.storage_type
93    }
94
95    /// Returns `true` if the underlying component type can be freely shared between threads.
96    /// If this returns `false`, then extra care must be taken to ensure that components
97    /// are not accessed from the wrong thread.
98    #[inline]
99    pub fn is_send_and_sync(&self) -> bool {
100        self.descriptor.is_send_and_sync
101    }
102
103    /// Create a new [`ComponentInfo`].
104    pub(crate) fn new(id: ComponentId, descriptor: ComponentDescriptor) -> Self {
105        ComponentInfo {
106            id,
107            descriptor,
108            hooks: Default::default(),
109            required_components: Default::default(),
110            required_by: Default::default(),
111        }
112    }
113
114    /// Update the given flags to include any [`ComponentHook`](crate::component::ComponentHook) registered to self
115    #[inline]
116    pub(crate) fn update_archetype_flags(&self, flags: &mut ArchetypeFlags) {
117        if self.hooks().on_add.is_some() {
118            flags.insert(ArchetypeFlags::ON_ADD_HOOK);
119        }
120        if self.hooks().on_insert.is_some() {
121            flags.insert(ArchetypeFlags::ON_INSERT_HOOK);
122        }
123        if self.hooks().on_replace.is_some() {
124            flags.insert(ArchetypeFlags::ON_REPLACE_HOOK);
125        }
126        if self.hooks().on_remove.is_some() {
127            flags.insert(ArchetypeFlags::ON_REMOVE_HOOK);
128        }
129        if self.hooks().on_despawn.is_some() {
130            flags.insert(ArchetypeFlags::ON_DESPAWN_HOOK);
131        }
132    }
133
134    /// Provides a reference to the collection of hooks associated with this [`Component`]
135    pub fn hooks(&self) -> &ComponentHooks {
136        &self.hooks
137    }
138
139    /// Retrieves the [`RequiredComponents`] collection, which contains all required components (and their constructors)
140    /// needed by this component. This includes _recursive_ required components.
141    pub fn required_components(&self) -> &RequiredComponents {
142        &self.required_components
143    }
144
145    /// Returns [`RelationshipAccessor`] for this component if it is a [`Relationship`](crate::relationship::Relationship) or [`RelationshipTarget`](crate::relationship::RelationshipTarget) , `None` otherwise.
146    pub fn relationship_accessor(&self) -> Option<&RelationshipAccessor> {
147        self.descriptor.relationship_accessor.as_ref()
148    }
149}
150
151/// A value which uniquely identifies the type of a [`Component`] or [`Resource`] within a
152/// [`World`](crate::world::World).
153///
154/// Each time a new `Component` type is registered within a `World` using
155/// e.g. [`World::register_component`](crate::world::World::register_component) or
156/// [`World::register_component_with_descriptor`](crate::world::World::register_component_with_descriptor)
157/// or a Resource with e.g. [`World::init_resource`](crate::world::World::init_resource),
158/// a corresponding `ComponentId` is created to track it.
159///
160/// While the distinction between `ComponentId` and [`TypeId`] may seem superficial, breaking them
161/// into two separate but related concepts allows components to exist outside of Rust's type system.
162/// Each Rust type registered as a `Component` will have a corresponding `ComponentId`, but additional
163/// `ComponentId`s may exist in a `World` to track components which cannot be
164/// represented as Rust types for scripting or other advanced use-cases.
165///
166/// A `ComponentId` is tightly coupled to its parent `World`. Attempting to use a `ComponentId` from
167/// one `World` to access the metadata of a `Component` in a different `World` is undefined behavior
168/// and must not be attempted.
169///
170/// Given a type `T` which implements [`Component`], the `ComponentId` for `T` can be retrieved
171/// from a `World` using [`World::component_id()`](crate::world::World::component_id) or via [`Components::component_id()`].
172/// Access to the `ComponentId` for a [`Resource`] is available via [`Components::resource_id()`].
173#[derive(Debug, Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
174#[cfg_attr(
175    feature = "bevy_reflect",
176    derive(Reflect),
177    reflect(Debug, Hash, PartialEq, Clone)
178)]
179pub struct ComponentId(pub(super) usize);
180
181impl ComponentId {
182    /// Creates a new [`ComponentId`].
183    ///
184    /// The `index` is a unique value associated with each type of component in a given world.
185    /// Usually, this value is taken from a counter incremented for each type of component registered with the world.
186    #[inline]
187    pub const fn new(index: usize) -> ComponentId {
188        ComponentId(index)
189    }
190
191    /// Returns the index of the current component.
192    #[inline]
193    pub fn index(self) -> usize {
194        self.0
195    }
196}
197
198impl SparseSetIndex for ComponentId {
199    #[inline]
200    fn sparse_set_index(&self) -> usize {
201        self.index()
202    }
203
204    #[inline]
205    fn get_sparse_set_index(value: usize) -> Self {
206        Self(value)
207    }
208}
209
210/// A value describing a component or resource, which may or may not correspond to a Rust type.
211#[derive(Clone)]
212pub struct ComponentDescriptor {
213    name: DebugName,
214    // SAFETY: This must remain private. It must match the statically known StorageType of the
215    // associated rust component type if one exists.
216    storage_type: StorageType,
217    // SAFETY: This must remain private. It must only be set to "true" if this component is
218    // actually Send + Sync
219    is_send_and_sync: bool,
220    type_id: Option<TypeId>,
221    layout: Layout,
222    // SAFETY: this function must be safe to call with pointers pointing to items of the type
223    // this descriptor describes.
224    // None if the underlying type doesn't need to be dropped
225    drop: Option<for<'a> unsafe fn(OwningPtr<'a>)>,
226    mutable: bool,
227    clone_behavior: ComponentCloneBehavior,
228    relationship_accessor: Option<RelationshipAccessor>,
229}
230
231// We need to ignore the `drop` field in our `Debug` impl
232impl Debug for ComponentDescriptor {
233    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
234        f.debug_struct("ComponentDescriptor")
235            .field("name", &self.name)
236            .field("storage_type", &self.storage_type)
237            .field("is_send_and_sync", &self.is_send_and_sync)
238            .field("type_id", &self.type_id)
239            .field("layout", &self.layout)
240            .field("mutable", &self.mutable)
241            .field("clone_behavior", &self.clone_behavior)
242            .field("relationship_accessor", &self.relationship_accessor)
243            .finish()
244    }
245}
246
247impl ComponentDescriptor {
248    /// # Safety
249    ///
250    /// `x` must point to a valid value of type `T`.
251    unsafe fn drop_ptr<T>(x: OwningPtr<'_>) {
252        // SAFETY: Contract is required to be upheld by the caller.
253        unsafe {
254            x.drop_as::<T>();
255        }
256    }
257
258    /// Create a new `ComponentDescriptor` for the type `T`.
259    pub fn new<T: Component>() -> Self {
260        Self {
261            name: DebugName::type_name::<T>(),
262            storage_type: T::STORAGE_TYPE,
263            is_send_and_sync: true,
264            type_id: Some(TypeId::of::<T>()),
265            layout: Layout::new::<T>(),
266            drop: needs_drop::<T>().then_some(Self::drop_ptr::<T> as _),
267            mutable: T::Mutability::MUTABLE,
268            clone_behavior: T::clone_behavior(),
269            relationship_accessor: T::relationship_accessor().map(|v| v.accessor),
270        }
271    }
272
273    /// Create a new `ComponentDescriptor`.
274    ///
275    /// # Safety
276    /// - the `drop` fn must be usable on a pointer with a value of the layout `layout`
277    /// - the component type must be safe to access from any thread (Send + Sync in rust terms)
278    /// - `relationship_accessor` must be valid for this component type if not `None`
279    pub unsafe fn new_with_layout(
280        name: impl Into<Cow<'static, str>>,
281        storage_type: StorageType,
282        layout: Layout,
283        drop: Option<for<'a> unsafe fn(OwningPtr<'a>)>,
284        mutable: bool,
285        clone_behavior: ComponentCloneBehavior,
286        relationship_accessor: Option<RelationshipAccessor>,
287    ) -> Self {
288        Self {
289            name: name.into().into(),
290            storage_type,
291            is_send_and_sync: true,
292            type_id: None,
293            layout,
294            drop,
295            mutable,
296            clone_behavior,
297            relationship_accessor,
298        }
299    }
300
301    /// Create a new `ComponentDescriptor` for a resource.
302    ///
303    /// The [`StorageType`] for resources is always [`StorageType::Table`].
304    pub fn new_resource<T: Resource>() -> Self {
305        Self {
306            name: DebugName::type_name::<T>(),
307            // PERF: `SparseStorage` may actually be a more
308            // reasonable choice as `storage_type` for resources.
309            storage_type: StorageType::Table,
310            is_send_and_sync: true,
311            type_id: Some(TypeId::of::<T>()),
312            layout: Layout::new::<T>(),
313            drop: needs_drop::<T>().then_some(Self::drop_ptr::<T> as _),
314            mutable: true,
315            clone_behavior: ComponentCloneBehavior::Default,
316            relationship_accessor: None,
317        }
318    }
319
320    pub(super) fn new_non_send<T: Any>(storage_type: StorageType) -> Self {
321        Self {
322            name: DebugName::type_name::<T>(),
323            storage_type,
324            is_send_and_sync: false,
325            type_id: Some(TypeId::of::<T>()),
326            layout: Layout::new::<T>(),
327            drop: needs_drop::<T>().then_some(Self::drop_ptr::<T> as _),
328            mutable: true,
329            clone_behavior: ComponentCloneBehavior::Default,
330            relationship_accessor: None,
331        }
332    }
333
334    /// Returns a value indicating the storage strategy for the current component.
335    #[inline]
336    pub fn storage_type(&self) -> StorageType {
337        self.storage_type
338    }
339
340    /// Returns the [`TypeId`] of the underlying component type.
341    /// Returns `None` if the component does not correspond to a Rust type.
342    #[inline]
343    pub fn type_id(&self) -> Option<TypeId> {
344        self.type_id
345    }
346
347    /// Returns the name of the current component.
348    #[inline]
349    pub fn name(&self) -> DebugName {
350        self.name.clone()
351    }
352
353    /// Returns whether this component is mutable.
354    #[inline]
355    pub fn mutable(&self) -> bool {
356        self.mutable
357    }
358}
359
360/// Stores metadata associated with each kind of [`Component`] in a given [`World`](crate::world::World).
361#[derive(Debug, Default)]
362pub struct Components {
363    pub(super) components: Vec<Option<ComponentInfo>>,
364    pub(super) indices: TypeIdMap<ComponentId>,
365    pub(super) resource_indices: TypeIdMap<ComponentId>,
366    // This is kept internal and local to verify that no deadlocks can occur.
367    pub(super) queued: bevy_platform::sync::RwLock<QueuedComponents>,
368}
369
370impl Components {
371    /// This registers any descriptor, component or resource.
372    ///
373    /// # Safety
374    ///
375    /// The id must have never been registered before. This must be a fresh registration.
376    #[inline]
377    pub(super) unsafe fn register_component_inner(
378        &mut self,
379        id: ComponentId,
380        descriptor: ComponentDescriptor,
381    ) {
382        let info = ComponentInfo::new(id, descriptor);
383        let least_len = id.0 + 1;
384        if self.components.len() < least_len {
385            self.components.resize_with(least_len, || None);
386        }
387        // SAFETY: We just extended the vec to make this index valid.
388        let slot = unsafe { self.components.get_mut(id.0).debug_checked_unwrap() };
389        // Caller ensures id is unique
390        debug_assert!(slot.is_none());
391        *slot = Some(info);
392    }
393
394    /// Returns the number of components registered or queued with this instance.
395    #[inline]
396    pub fn len(&self) -> usize {
397        self.num_queued() + self.num_registered()
398    }
399
400    /// Returns `true` if there are no components registered or queued with this instance. Otherwise, this returns `false`.
401    #[inline]
402    pub fn is_empty(&self) -> bool {
403        self.len() == 0
404    }
405
406    /// Returns the number of components registered with this instance.
407    #[inline]
408    pub fn num_queued(&self) -> usize {
409        let queued = self.queued.read().unwrap_or_else(PoisonError::into_inner);
410        queued.components.len() + queued.dynamic_registrations.len() + queued.resources.len()
411    }
412
413    /// Returns `true` if there are any components registered with this instance. Otherwise, this returns `false`.
414    #[inline]
415    pub fn any_queued(&self) -> bool {
416        self.num_queued() > 0
417    }
418
419    /// A faster version of [`Self::num_queued`].
420    #[inline]
421    pub fn num_queued_mut(&mut self) -> usize {
422        let queued = self
423            .queued
424            .get_mut()
425            .unwrap_or_else(PoisonError::into_inner);
426        queued.components.len() + queued.dynamic_registrations.len() + queued.resources.len()
427    }
428
429    /// A faster version of [`Self::any_queued`].
430    #[inline]
431    pub fn any_queued_mut(&mut self) -> bool {
432        self.num_queued_mut() > 0
433    }
434
435    /// Returns the number of components registered with this instance.
436    #[inline]
437    pub fn num_registered(&self) -> usize {
438        self.components.len()
439    }
440
441    /// Returns `true` if there are any components registered with this instance. Otherwise, this returns `false`.
442    #[inline]
443    pub fn any_registered(&self) -> bool {
444        self.num_registered() > 0
445    }
446
447    /// Gets the metadata associated with the given component, if it is registered.
448    /// This will return `None` if the id is not registered or is queued.
449    ///
450    /// 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.
451    #[inline]
452    pub fn get_info(&self, id: ComponentId) -> Option<&ComponentInfo> {
453        self.components.get(id.0).and_then(|info| info.as_ref())
454    }
455
456    /// Gets the [`ComponentDescriptor`] of the component with this [`ComponentId`] if it is present.
457    /// This will return `None` only if the id is neither registered nor queued to be registered.
458    ///
459    /// Currently, the [`Cow`] will be [`Cow::Owned`] if and only if the component is queued. It will be [`Cow::Borrowed`] otherwise.
460    ///
461    /// 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.
462    #[inline]
463    pub fn get_descriptor<'a>(&'a self, id: ComponentId) -> Option<Cow<'a, ComponentDescriptor>> {
464        self.components
465            .get(id.0)
466            .and_then(|info| info.as_ref().map(|info| Cow::Borrowed(&info.descriptor)))
467            .or_else(|| {
468                let queued = self.queued.read().unwrap_or_else(PoisonError::into_inner);
469                // first check components, then resources, then dynamic
470                queued
471                    .components
472                    .values()
473                    .chain(queued.resources.values())
474                    .chain(queued.dynamic_registrations.iter())
475                    .find(|queued| queued.id == id)
476                    .map(|queued| Cow::Owned(queued.descriptor.clone()))
477            })
478    }
479
480    /// Gets the name of the component with this [`ComponentId`] if it is present.
481    /// This will return `None` only if the id is neither registered nor queued to be registered.
482    ///
483    /// 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.
484    #[inline]
485    pub fn get_name<'a>(&'a self, id: ComponentId) -> Option<DebugName> {
486        self.components
487            .get(id.0)
488            .and_then(|info| info.as_ref().map(|info| info.descriptor.name()))
489            .or_else(|| {
490                let queued = self.queued.read().unwrap_or_else(PoisonError::into_inner);
491                // first check components, then resources, then dynamic
492                queued
493                    .components
494                    .values()
495                    .chain(queued.resources.values())
496                    .chain(queued.dynamic_registrations.iter())
497                    .find(|queued| queued.id == id)
498                    .map(|queued| queued.descriptor.name.clone())
499            })
500    }
501
502    /// Gets the metadata associated with the given component.
503    /// # Safety
504    ///
505    /// `id` must be a valid and fully registered [`ComponentId`].
506    #[inline]
507    pub unsafe fn get_info_unchecked(&self, id: ComponentId) -> &ComponentInfo {
508        // SAFETY: The caller ensures `id` is valid.
509        unsafe {
510            self.components
511                .get(id.0)
512                .debug_checked_unwrap()
513                .as_ref()
514                .debug_checked_unwrap()
515        }
516    }
517
518    #[inline]
519    pub(crate) fn get_hooks_mut(&mut self, id: ComponentId) -> Option<&mut ComponentHooks> {
520        self.components
521            .get_mut(id.0)
522            .and_then(|info| info.as_mut().map(|info| &mut info.hooks))
523    }
524
525    #[inline]
526    pub(crate) fn get_required_components(&self, id: ComponentId) -> Option<&RequiredComponents> {
527        self.components
528            .get(id.0)
529            .and_then(|info| info.as_ref().map(|info| &info.required_components))
530    }
531
532    #[inline]
533    pub(crate) fn get_required_components_mut(
534        &mut self,
535        id: ComponentId,
536    ) -> Option<&mut RequiredComponents> {
537        self.components
538            .get_mut(id.0)
539            .and_then(|info| info.as_mut().map(|info| &mut info.required_components))
540    }
541
542    #[inline]
543    pub(crate) fn get_required_by(
544        &self,
545        id: ComponentId,
546    ) -> Option<&IndexSet<ComponentId, FixedHasher>> {
547        self.components
548            .get(id.0)
549            .and_then(|info| info.as_ref().map(|info| &info.required_by))
550    }
551
552    #[inline]
553    pub(crate) fn get_required_by_mut(
554        &mut self,
555        id: ComponentId,
556    ) -> Option<&mut IndexSet<ComponentId, FixedHasher>> {
557        self.components
558            .get_mut(id.0)
559            .and_then(|info| info.as_mut().map(|info| &mut info.required_by))
560    }
561
562    /// Returns true if the [`ComponentId`] is fully registered and valid.
563    /// Ids may be invalid if they are still queued to be registered.
564    /// Those ids are still correct, but they are not usable in every context yet.
565    #[inline]
566    pub fn is_id_valid(&self, id: ComponentId) -> bool {
567        self.components.get(id.0).is_some_and(Option::is_some)
568    }
569
570    /// Type-erased equivalent of [`Components::valid_component_id()`].
571    #[inline]
572    pub fn get_valid_id(&self, type_id: TypeId) -> Option<ComponentId> {
573        self.indices.get(&type_id).copied()
574    }
575
576    /// Returns the [`ComponentId`] of the given [`Component`] type `T` if it is fully registered.
577    /// If you want to include queued registration, see [`Components::component_id()`].
578    ///
579    /// ```
580    /// use bevy_ecs::prelude::*;
581    ///
582    /// let mut world = World::new();
583    ///
584    /// #[derive(Component)]
585    /// struct ComponentA;
586    ///
587    /// let component_a_id = world.register_component::<ComponentA>();
588    ///
589    /// assert_eq!(component_a_id, world.components().valid_component_id::<ComponentA>().unwrap())
590    /// ```
591    ///
592    /// # See also
593    ///
594    /// * [`Components::get_valid_id()`]
595    /// * [`Components::valid_resource_id()`]
596    /// * [`World::component_id()`](crate::world::World::component_id)
597    #[inline]
598    pub fn valid_component_id<T: Component>(&self) -> Option<ComponentId> {
599        self.get_valid_id(TypeId::of::<T>())
600    }
601
602    /// Type-erased equivalent of [`Components::valid_resource_id()`].
603    #[inline]
604    pub fn get_valid_resource_id(&self, type_id: TypeId) -> Option<ComponentId> {
605        self.resource_indices.get(&type_id).copied()
606    }
607
608    /// Returns the [`ComponentId`] of the given [`Resource`] type `T` if it is fully registered.
609    /// If you want to include queued registration, see [`Components::resource_id()`].
610    ///
611    /// ```
612    /// use bevy_ecs::prelude::*;
613    ///
614    /// let mut world = World::new();
615    ///
616    /// #[derive(Resource, Default)]
617    /// struct ResourceA;
618    ///
619    /// let resource_a_id = world.init_resource::<ResourceA>();
620    ///
621    /// assert_eq!(resource_a_id, world.components().valid_resource_id::<ResourceA>().unwrap())
622    /// ```
623    ///
624    /// # See also
625    ///
626    /// * [`Components::valid_component_id()`]
627    /// * [`Components::get_resource_id()`]
628    #[inline]
629    pub fn valid_resource_id<T: Resource>(&self) -> Option<ComponentId> {
630        self.get_valid_resource_id(TypeId::of::<T>())
631    }
632
633    /// Type-erased equivalent of [`Components::component_id()`].
634    #[inline]
635    pub fn get_id(&self, type_id: TypeId) -> Option<ComponentId> {
636        self.indices.get(&type_id).copied().or_else(|| {
637            self.queued
638                .read()
639                .unwrap_or_else(PoisonError::into_inner)
640                .components
641                .get(&type_id)
642                .map(|queued| queued.id)
643        })
644    }
645
646    /// Returns the [`ComponentId`] of the given [`Component`] type `T`.
647    ///
648    /// The returned `ComponentId` is specific to the `Components` instance
649    /// it was retrieved from and should not be used with another `Components`
650    /// instance.
651    ///
652    /// Returns [`None`] if the `Component` type has not yet been initialized using
653    /// [`ComponentsRegistrator::register_component()`](super::ComponentsRegistrator::register_component) or
654    /// [`ComponentsQueuedRegistrator::queue_register_component()`](super::ComponentsQueuedRegistrator::queue_register_component).
655    ///
656    /// ```
657    /// use bevy_ecs::prelude::*;
658    ///
659    /// let mut world = World::new();
660    ///
661    /// #[derive(Component)]
662    /// struct ComponentA;
663    ///
664    /// let component_a_id = world.register_component::<ComponentA>();
665    ///
666    /// assert_eq!(component_a_id, world.components().component_id::<ComponentA>().unwrap())
667    /// ```
668    ///
669    /// # See also
670    ///
671    /// * [`ComponentIdFor`](super::ComponentIdFor)
672    /// * [`Components::get_id()`]
673    /// * [`Components::resource_id()`]
674    /// * [`World::component_id()`](crate::world::World::component_id)
675    #[inline]
676    pub fn component_id<T: Component>(&self) -> Option<ComponentId> {
677        self.get_id(TypeId::of::<T>())
678    }
679
680    /// Type-erased equivalent of [`Components::resource_id()`].
681    #[inline]
682    pub fn get_resource_id(&self, type_id: TypeId) -> Option<ComponentId> {
683        self.resource_indices.get(&type_id).copied().or_else(|| {
684            self.queued
685                .read()
686                .unwrap_or_else(PoisonError::into_inner)
687                .resources
688                .get(&type_id)
689                .map(|queued| queued.id)
690        })
691    }
692
693    /// Returns the [`ComponentId`] of the given [`Resource`] type `T`.
694    ///
695    /// The returned `ComponentId` is specific to the `Components` instance
696    /// it was retrieved from and should not be used with another `Components`
697    /// instance.
698    ///
699    /// Returns [`None`] if the `Resource` type has not yet been initialized using
700    /// [`ComponentsRegistrator::register_resource()`](super::ComponentsRegistrator::register_resource) or
701    /// [`ComponentsQueuedRegistrator::queue_register_resource()`](super::ComponentsQueuedRegistrator::queue_register_resource).
702    ///
703    /// ```
704    /// use bevy_ecs::prelude::*;
705    ///
706    /// let mut world = World::new();
707    ///
708    /// #[derive(Resource, Default)]
709    /// struct ResourceA;
710    ///
711    /// let resource_a_id = world.init_resource::<ResourceA>();
712    ///
713    /// assert_eq!(resource_a_id, world.components().resource_id::<ResourceA>().unwrap())
714    /// ```
715    ///
716    /// # See also
717    ///
718    /// * [`Components::component_id()`]
719    /// * [`Components::get_resource_id()`]
720    #[inline]
721    pub fn resource_id<T: Resource>(&self) -> Option<ComponentId> {
722        self.get_resource_id(TypeId::of::<T>())
723    }
724
725    /// # Safety
726    ///
727    /// The [`ComponentDescriptor`] must match the [`TypeId`].
728    /// The [`ComponentId`] must be unique.
729    /// The [`TypeId`] and [`ComponentId`] must not be registered or queued.
730    #[inline]
731    pub(super) unsafe fn register_resource_unchecked(
732        &mut self,
733        type_id: TypeId,
734        component_id: ComponentId,
735        descriptor: ComponentDescriptor,
736    ) {
737        // SAFETY: ensured by caller
738        unsafe {
739            self.register_component_inner(component_id, descriptor);
740        }
741        let prev = self.resource_indices.insert(type_id, component_id);
742        debug_assert!(prev.is_none());
743    }
744
745    /// Gets an iterator over all components fully registered with this instance.
746    pub fn iter_registered(&self) -> impl Iterator<Item = &ComponentInfo> + '_ {
747        self.components.iter().filter_map(Option::as_ref)
748    }
749}