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