Skip to main content

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