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}