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}