Extract other registration items with queued ones
This commit is contained in:
parent
d92a19fbc1
commit
7ed08cc082
@ -2,33 +2,25 @@
|
||||
|
||||
mod clone;
|
||||
mod info;
|
||||
mod queued_registration;
|
||||
mod register;
|
||||
mod required;
|
||||
mod tick;
|
||||
|
||||
pub use clone::*;
|
||||
pub use info::*;
|
||||
pub use queued_registration::*;
|
||||
pub use register::*;
|
||||
pub use required::*;
|
||||
pub use tick::*;
|
||||
|
||||
use crate::{
|
||||
entity::EntityMapper,
|
||||
lifecycle::ComponentHook,
|
||||
query::DebugCheckedUnwrap,
|
||||
resource::Resource,
|
||||
system::{Local, SystemParam},
|
||||
world::{FromWorld, World},
|
||||
};
|
||||
use alloc::vec::Vec;
|
||||
pub use bevy_ecs_macros::Component;
|
||||
use bevy_platform::sync::PoisonError;
|
||||
use core::{
|
||||
any::{Any, TypeId},
|
||||
fmt::Debug,
|
||||
marker::PhantomData,
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
use core::{fmt::Debug, marker::PhantomData, ops::Deref};
|
||||
|
||||
/// A data type that can be used to store data for an [entity].
|
||||
///
|
||||
@ -712,362 +704,6 @@ pub enum StorageType {
|
||||
SparseSet,
|
||||
}
|
||||
|
||||
/// Generates [`ComponentId`]s.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ComponentIds {
|
||||
next: bevy_platform::sync::atomic::AtomicUsize,
|
||||
}
|
||||
|
||||
impl ComponentIds {
|
||||
/// Peeks the next [`ComponentId`] to be generated without generating it.
|
||||
pub fn peek(&self) -> ComponentId {
|
||||
ComponentId(
|
||||
self.next
|
||||
.load(bevy_platform::sync::atomic::Ordering::Relaxed),
|
||||
)
|
||||
}
|
||||
|
||||
/// Generates and returns the next [`ComponentId`].
|
||||
pub fn next(&self) -> ComponentId {
|
||||
ComponentId(
|
||||
self.next
|
||||
.fetch_add(1, bevy_platform::sync::atomic::Ordering::Relaxed),
|
||||
)
|
||||
}
|
||||
|
||||
/// Peeks the next [`ComponentId`] to be generated without generating it.
|
||||
pub fn peek_mut(&mut self) -> ComponentId {
|
||||
ComponentId(*self.next.get_mut())
|
||||
}
|
||||
|
||||
/// Generates and returns the next [`ComponentId`].
|
||||
pub fn next_mut(&mut self) -> ComponentId {
|
||||
let id = self.next.get_mut();
|
||||
let result = ComponentId(*id);
|
||||
*id += 1;
|
||||
result
|
||||
}
|
||||
|
||||
/// Returns the number of [`ComponentId`]s generated.
|
||||
pub fn len(&self) -> usize {
|
||||
self.peek().0
|
||||
}
|
||||
|
||||
/// Returns true if and only if no ids have been generated.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`Components`] wrapper that enables additional features, like registration.
|
||||
pub struct ComponentsRegistrator<'w> {
|
||||
components: &'w mut Components,
|
||||
ids: &'w mut ComponentIds,
|
||||
}
|
||||
|
||||
impl Deref for ComponentsRegistrator<'_> {
|
||||
type Target = Components;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.components
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for ComponentsRegistrator<'_> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.components
|
||||
}
|
||||
}
|
||||
|
||||
impl<'w> ComponentsRegistrator<'w> {
|
||||
/// Constructs a new [`ComponentsRegistrator`].
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The [`Components`] and [`ComponentIds`] must match.
|
||||
/// For example, they must be from the same world.
|
||||
pub unsafe fn new(components: &'w mut Components, ids: &'w mut ComponentIds) -> Self {
|
||||
Self { components, ids }
|
||||
}
|
||||
|
||||
/// Converts this [`ComponentsRegistrator`] into a [`ComponentsQueuedRegistrator`].
|
||||
/// This is intended for use to pass this value to a function that requires [`ComponentsQueuedRegistrator`].
|
||||
/// It is generally not a good idea to queue a registration when you can instead register directly on this type.
|
||||
pub fn as_queued(&self) -> ComponentsQueuedRegistrator<'_> {
|
||||
// SAFETY: ensured by the caller that created self.
|
||||
unsafe { ComponentsQueuedRegistrator::new(self.components, self.ids) }
|
||||
}
|
||||
|
||||
/// Applies every queued registration.
|
||||
/// This ensures that every valid [`ComponentId`] is registered,
|
||||
/// enabling retrieving [`ComponentInfo`], etc.
|
||||
pub fn apply_queued_registrations(&mut self) {
|
||||
if !self.any_queued_mut() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Note:
|
||||
//
|
||||
// This is not just draining the queue. We need to empty the queue without removing the information from `Components`.
|
||||
// If we drained directly, we could break invariance.
|
||||
//
|
||||
// For example, say `ComponentA` and `ComponentB` are queued, and `ComponentA` requires `ComponentB`.
|
||||
// If we drain directly, and `ComponentA` was the first to be registered, then, when `ComponentA`
|
||||
// registers `ComponentB` in `Component::register_required_components`,
|
||||
// `Components` will not know that `ComponentB` was queued
|
||||
// (since it will have been drained from the queue.)
|
||||
// If that happened, `Components` would assign a new `ComponentId` to `ComponentB`
|
||||
// which would be *different* than the id it was assigned in the queue.
|
||||
// Then, when the drain iterator gets to `ComponentB`,
|
||||
// it would be unsafely registering `ComponentB`, which is already registered.
|
||||
//
|
||||
// As a result, we need to pop from each queue one by one instead of draining.
|
||||
|
||||
// components
|
||||
while let Some(registrator) = {
|
||||
let queued = self
|
||||
.components
|
||||
.queued
|
||||
.get_mut()
|
||||
.unwrap_or_else(PoisonError::into_inner);
|
||||
queued.components.keys().next().copied().map(|type_id| {
|
||||
// SAFETY: the id just came from a valid iterator.
|
||||
unsafe { queued.components.remove(&type_id).debug_checked_unwrap() }
|
||||
})
|
||||
} {
|
||||
registrator.register(self);
|
||||
}
|
||||
|
||||
// resources
|
||||
while let Some(registrator) = {
|
||||
let queued = self
|
||||
.components
|
||||
.queued
|
||||
.get_mut()
|
||||
.unwrap_or_else(PoisonError::into_inner);
|
||||
queued.resources.keys().next().copied().map(|type_id| {
|
||||
// SAFETY: the id just came from a valid iterator.
|
||||
unsafe { queued.resources.remove(&type_id).debug_checked_unwrap() }
|
||||
})
|
||||
} {
|
||||
registrator.register(self);
|
||||
}
|
||||
|
||||
// dynamic
|
||||
let queued = &mut self
|
||||
.components
|
||||
.queued
|
||||
.get_mut()
|
||||
.unwrap_or_else(PoisonError::into_inner);
|
||||
if !queued.dynamic_registrations.is_empty() {
|
||||
for registrator in core::mem::take(&mut queued.dynamic_registrations) {
|
||||
registrator.register(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Registers a [`Component`] of type `T` with this instance.
|
||||
/// If a component of this type has already been registered, this will return
|
||||
/// the ID of the pre-existing component.
|
||||
///
|
||||
/// # See also
|
||||
///
|
||||
/// * [`Components::component_id()`]
|
||||
/// * [`ComponentsRegistrator::register_component_with_descriptor()`]
|
||||
#[inline]
|
||||
pub fn register_component<T: Component>(&mut self) -> ComponentId {
|
||||
self.register_component_checked::<T>(&mut Vec::new())
|
||||
}
|
||||
|
||||
/// Same as [`Self::register_component_unchecked`] but keeps a checks for safety.
|
||||
#[inline]
|
||||
fn register_component_checked<T: Component>(
|
||||
&mut self,
|
||||
recursion_check_stack: &mut Vec<ComponentId>,
|
||||
) -> ComponentId {
|
||||
let type_id = TypeId::of::<T>();
|
||||
if let Some(id) = self.indices.get(&type_id) {
|
||||
return *id;
|
||||
}
|
||||
|
||||
if let Some(registrator) = self
|
||||
.components
|
||||
.queued
|
||||
.get_mut()
|
||||
.unwrap_or_else(PoisonError::into_inner)
|
||||
.components
|
||||
.remove(&type_id)
|
||||
{
|
||||
// If we are trying to register something that has already been queued, we respect the queue.
|
||||
// Just like if we are trying to register something that already is, we respect the first registration.
|
||||
return registrator.register(self);
|
||||
}
|
||||
|
||||
let id = self.ids.next_mut();
|
||||
// SAFETY: The component is not currently registered, and the id is fresh.
|
||||
unsafe {
|
||||
self.register_component_unchecked::<T>(recursion_check_stack, id);
|
||||
}
|
||||
id
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// Neither this component, nor its id may be registered or queued. This must be a new registration.
|
||||
#[inline]
|
||||
unsafe fn register_component_unchecked<T: Component>(
|
||||
&mut self,
|
||||
recursion_check_stack: &mut Vec<ComponentId>,
|
||||
id: ComponentId,
|
||||
) {
|
||||
// SAFETY: ensured by caller.
|
||||
unsafe {
|
||||
self.register_component_inner(id, ComponentDescriptor::new::<T>());
|
||||
}
|
||||
let type_id = TypeId::of::<T>();
|
||||
let prev = self.indices.insert(type_id, id);
|
||||
debug_assert!(prev.is_none());
|
||||
|
||||
let mut required_components = RequiredComponents::default();
|
||||
T::register_required_components(
|
||||
id,
|
||||
self,
|
||||
&mut required_components,
|
||||
0,
|
||||
recursion_check_stack,
|
||||
);
|
||||
// SAFETY: we just inserted it in `register_component_inner`
|
||||
let info = unsafe {
|
||||
&mut self
|
||||
.components
|
||||
.components
|
||||
.get_mut(id.0)
|
||||
.debug_checked_unwrap()
|
||||
.as_mut()
|
||||
.debug_checked_unwrap()
|
||||
};
|
||||
|
||||
info.hooks.update_from_component::<T>();
|
||||
|
||||
info.required_components = required_components;
|
||||
}
|
||||
|
||||
/// Registers a component described by `descriptor`.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// If this method is called multiple times with identical descriptors, a distinct [`ComponentId`]
|
||||
/// will be created for each one.
|
||||
///
|
||||
/// # See also
|
||||
///
|
||||
/// * [`Components::component_id()`]
|
||||
/// * [`ComponentsRegistrator::register_component()`]
|
||||
#[inline]
|
||||
pub fn register_component_with_descriptor(
|
||||
&mut self,
|
||||
descriptor: ComponentDescriptor,
|
||||
) -> ComponentId {
|
||||
let id = self.ids.next_mut();
|
||||
// SAFETY: The id is fresh.
|
||||
unsafe {
|
||||
self.register_component_inner(id, descriptor);
|
||||
}
|
||||
id
|
||||
}
|
||||
|
||||
/// Registers a [`Resource`] of type `T` with this instance.
|
||||
/// If a resource of this type has already been registered, this will return
|
||||
/// the ID of the pre-existing resource.
|
||||
///
|
||||
/// # See also
|
||||
///
|
||||
/// * [`Components::resource_id()`]
|
||||
/// * [`ComponentsRegistrator::register_resource_with_descriptor()`]
|
||||
#[inline]
|
||||
pub fn register_resource<T: Resource>(&mut self) -> ComponentId {
|
||||
// SAFETY: The [`ComponentDescriptor`] matches the [`TypeId`]
|
||||
unsafe {
|
||||
self.register_resource_with(TypeId::of::<T>(), || {
|
||||
ComponentDescriptor::new_resource::<T>()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Registers a [non-send resource](crate::system::NonSend) of type `T` with this instance.
|
||||
/// If a resource of this type has already been registered, this will return
|
||||
/// the ID of the pre-existing resource.
|
||||
#[inline]
|
||||
pub fn register_non_send<T: Any>(&mut self) -> ComponentId {
|
||||
// SAFETY: The [`ComponentDescriptor`] matches the [`TypeId`]
|
||||
unsafe {
|
||||
self.register_resource_with(TypeId::of::<T>(), || {
|
||||
ComponentDescriptor::new_non_send::<T>(StorageType::default())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Same as [`Components::register_resource_unchecked`] but handles safety.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The [`ComponentDescriptor`] must match the [`TypeId`].
|
||||
#[inline]
|
||||
unsafe fn register_resource_with(
|
||||
&mut self,
|
||||
type_id: TypeId,
|
||||
descriptor: impl FnOnce() -> ComponentDescriptor,
|
||||
) -> ComponentId {
|
||||
if let Some(id) = self.resource_indices.get(&type_id) {
|
||||
return *id;
|
||||
}
|
||||
|
||||
if let Some(registrator) = self
|
||||
.components
|
||||
.queued
|
||||
.get_mut()
|
||||
.unwrap_or_else(PoisonError::into_inner)
|
||||
.resources
|
||||
.remove(&type_id)
|
||||
{
|
||||
// If we are trying to register something that has already been queued, we respect the queue.
|
||||
// Just like if we are trying to register something that already is, we respect the first registration.
|
||||
return registrator.register(self);
|
||||
}
|
||||
|
||||
let id = self.ids.next_mut();
|
||||
// SAFETY: The resource is not currently registered, the id is fresh, and the [`ComponentDescriptor`] matches the [`TypeId`]
|
||||
unsafe {
|
||||
self.register_resource_unchecked(type_id, id, descriptor());
|
||||
}
|
||||
id
|
||||
}
|
||||
|
||||
/// Registers a [`Resource`] described by `descriptor`.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// If this method is called multiple times with identical descriptors, a distinct [`ComponentId`]
|
||||
/// will be created for each one.
|
||||
///
|
||||
/// # See also
|
||||
///
|
||||
/// * [`Components::resource_id()`]
|
||||
/// * [`ComponentsRegistrator::register_resource()`]
|
||||
#[inline]
|
||||
pub fn register_resource_with_descriptor(
|
||||
&mut self,
|
||||
descriptor: ComponentDescriptor,
|
||||
) -> ComponentId {
|
||||
let id = self.ids.next_mut();
|
||||
// SAFETY: The id is fresh.
|
||||
unsafe {
|
||||
self.register_component_inner(id, descriptor);
|
||||
}
|
||||
id
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`SystemParam`] that provides access to the [`ComponentId`] for a specific component type.
|
||||
///
|
||||
/// # Example
|
||||
|
@ -2,13 +2,372 @@ use alloc::{boxed::Box, vec::Vec};
|
||||
use bevy_platform::sync::PoisonError;
|
||||
use bevy_utils::TypeIdMap;
|
||||
use core::any::Any;
|
||||
use core::ops::DerefMut;
|
||||
use core::{any::TypeId, fmt::Debug, ops::Deref};
|
||||
|
||||
use crate::component::{
|
||||
Component, ComponentDescriptor, ComponentId, ComponentIds, Components, ComponentsRegistrator,
|
||||
StorageType,
|
||||
use crate::query::DebugCheckedUnwrap as _;
|
||||
use crate::{
|
||||
component::{
|
||||
Component, ComponentDescriptor, ComponentId, Components, RequiredComponents, StorageType,
|
||||
},
|
||||
resource::Resource,
|
||||
};
|
||||
use crate::resource::Resource;
|
||||
|
||||
/// Generates [`ComponentId`]s.
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ComponentIds {
|
||||
next: bevy_platform::sync::atomic::AtomicUsize,
|
||||
}
|
||||
|
||||
impl ComponentIds {
|
||||
/// Peeks the next [`ComponentId`] to be generated without generating it.
|
||||
pub fn peek(&self) -> ComponentId {
|
||||
ComponentId(
|
||||
self.next
|
||||
.load(bevy_platform::sync::atomic::Ordering::Relaxed),
|
||||
)
|
||||
}
|
||||
|
||||
/// Generates and returns the next [`ComponentId`].
|
||||
pub fn next(&self) -> ComponentId {
|
||||
ComponentId(
|
||||
self.next
|
||||
.fetch_add(1, bevy_platform::sync::atomic::Ordering::Relaxed),
|
||||
)
|
||||
}
|
||||
|
||||
/// Peeks the next [`ComponentId`] to be generated without generating it.
|
||||
pub fn peek_mut(&mut self) -> ComponentId {
|
||||
ComponentId(*self.next.get_mut())
|
||||
}
|
||||
|
||||
/// Generates and returns the next [`ComponentId`].
|
||||
pub fn next_mut(&mut self) -> ComponentId {
|
||||
let id = self.next.get_mut();
|
||||
let result = ComponentId(*id);
|
||||
*id += 1;
|
||||
result
|
||||
}
|
||||
|
||||
/// Returns the number of [`ComponentId`]s generated.
|
||||
pub fn len(&self) -> usize {
|
||||
self.peek().0
|
||||
}
|
||||
|
||||
/// Returns true if and only if no ids have been generated.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`Components`] wrapper that enables additional features, like registration.
|
||||
pub struct ComponentsRegistrator<'w> {
|
||||
components: &'w mut Components,
|
||||
ids: &'w mut ComponentIds,
|
||||
}
|
||||
|
||||
impl Deref for ComponentsRegistrator<'_> {
|
||||
type Target = Components;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.components
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for ComponentsRegistrator<'_> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.components
|
||||
}
|
||||
}
|
||||
|
||||
impl<'w> ComponentsRegistrator<'w> {
|
||||
/// Constructs a new [`ComponentsRegistrator`].
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The [`Components`] and [`ComponentIds`] must match.
|
||||
/// For example, they must be from the same world.
|
||||
pub unsafe fn new(components: &'w mut Components, ids: &'w mut ComponentIds) -> Self {
|
||||
Self { components, ids }
|
||||
}
|
||||
|
||||
/// Converts this [`ComponentsRegistrator`] into a [`ComponentsQueuedRegistrator`].
|
||||
/// This is intended for use to pass this value to a function that requires [`ComponentsQueuedRegistrator`].
|
||||
/// It is generally not a good idea to queue a registration when you can instead register directly on this type.
|
||||
pub fn as_queued(&self) -> ComponentsQueuedRegistrator<'_> {
|
||||
// SAFETY: ensured by the caller that created self.
|
||||
unsafe { ComponentsQueuedRegistrator::new(self.components, self.ids) }
|
||||
}
|
||||
|
||||
/// Applies every queued registration.
|
||||
/// This ensures that every valid [`ComponentId`] is registered,
|
||||
/// enabling retrieving [`ComponentInfo`], etc.
|
||||
pub fn apply_queued_registrations(&mut self) {
|
||||
if !self.any_queued_mut() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Note:
|
||||
//
|
||||
// This is not just draining the queue. We need to empty the queue without removing the information from `Components`.
|
||||
// If we drained directly, we could break invariance.
|
||||
//
|
||||
// For example, say `ComponentA` and `ComponentB` are queued, and `ComponentA` requires `ComponentB`.
|
||||
// If we drain directly, and `ComponentA` was the first to be registered, then, when `ComponentA`
|
||||
// registers `ComponentB` in `Component::register_required_components`,
|
||||
// `Components` will not know that `ComponentB` was queued
|
||||
// (since it will have been drained from the queue.)
|
||||
// If that happened, `Components` would assign a new `ComponentId` to `ComponentB`
|
||||
// which would be *different* than the id it was assigned in the queue.
|
||||
// Then, when the drain iterator gets to `ComponentB`,
|
||||
// it would be unsafely registering `ComponentB`, which is already registered.
|
||||
//
|
||||
// As a result, we need to pop from each queue one by one instead of draining.
|
||||
|
||||
// components
|
||||
while let Some(registrator) = {
|
||||
let queued = self
|
||||
.components
|
||||
.queued
|
||||
.get_mut()
|
||||
.unwrap_or_else(PoisonError::into_inner);
|
||||
queued.components.keys().next().copied().map(|type_id| {
|
||||
// SAFETY: the id just came from a valid iterator.
|
||||
unsafe { queued.components.remove(&type_id).debug_checked_unwrap() }
|
||||
})
|
||||
} {
|
||||
registrator.register(self);
|
||||
}
|
||||
|
||||
// resources
|
||||
while let Some(registrator) = {
|
||||
let queued = self
|
||||
.components
|
||||
.queued
|
||||
.get_mut()
|
||||
.unwrap_or_else(PoisonError::into_inner);
|
||||
queued.resources.keys().next().copied().map(|type_id| {
|
||||
// SAFETY: the id just came from a valid iterator.
|
||||
unsafe { queued.resources.remove(&type_id).debug_checked_unwrap() }
|
||||
})
|
||||
} {
|
||||
registrator.register(self);
|
||||
}
|
||||
|
||||
// dynamic
|
||||
let queued = &mut self
|
||||
.components
|
||||
.queued
|
||||
.get_mut()
|
||||
.unwrap_or_else(PoisonError::into_inner);
|
||||
if !queued.dynamic_registrations.is_empty() {
|
||||
for registrator in core::mem::take(&mut queued.dynamic_registrations) {
|
||||
registrator.register(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Registers a [`Component`] of type `T` with this instance.
|
||||
/// If a component of this type has already been registered, this will return
|
||||
/// the ID of the pre-existing component.
|
||||
///
|
||||
/// # See also
|
||||
///
|
||||
/// * [`Components::component_id()`]
|
||||
/// * [`ComponentsRegistrator::register_component_with_descriptor()`]
|
||||
#[inline]
|
||||
pub fn register_component<T: Component>(&mut self) -> ComponentId {
|
||||
self.register_component_checked::<T>(&mut Vec::new())
|
||||
}
|
||||
|
||||
/// Same as [`Self::register_component_unchecked`] but keeps a checks for safety.
|
||||
#[inline]
|
||||
pub(super) fn register_component_checked<T: Component>(
|
||||
&mut self,
|
||||
recursion_check_stack: &mut Vec<ComponentId>,
|
||||
) -> ComponentId {
|
||||
let type_id = TypeId::of::<T>();
|
||||
if let Some(id) = self.indices.get(&type_id) {
|
||||
return *id;
|
||||
}
|
||||
|
||||
if let Some(registrator) = self
|
||||
.components
|
||||
.queued
|
||||
.get_mut()
|
||||
.unwrap_or_else(PoisonError::into_inner)
|
||||
.components
|
||||
.remove(&type_id)
|
||||
{
|
||||
// If we are trying to register something that has already been queued, we respect the queue.
|
||||
// Just like if we are trying to register something that already is, we respect the first registration.
|
||||
return registrator.register(self);
|
||||
}
|
||||
|
||||
let id = self.ids.next_mut();
|
||||
// SAFETY: The component is not currently registered, and the id is fresh.
|
||||
unsafe {
|
||||
self.register_component_unchecked::<T>(recursion_check_stack, id);
|
||||
}
|
||||
id
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// Neither this component, nor its id may be registered or queued. This must be a new registration.
|
||||
#[inline]
|
||||
unsafe fn register_component_unchecked<T: Component>(
|
||||
&mut self,
|
||||
recursion_check_stack: &mut Vec<ComponentId>,
|
||||
id: ComponentId,
|
||||
) {
|
||||
// SAFETY: ensured by caller.
|
||||
unsafe {
|
||||
self.register_component_inner(id, ComponentDescriptor::new::<T>());
|
||||
}
|
||||
let type_id = TypeId::of::<T>();
|
||||
let prev = self.indices.insert(type_id, id);
|
||||
debug_assert!(prev.is_none());
|
||||
|
||||
let mut required_components = RequiredComponents::default();
|
||||
T::register_required_components(
|
||||
id,
|
||||
self,
|
||||
&mut required_components,
|
||||
0,
|
||||
recursion_check_stack,
|
||||
);
|
||||
// SAFETY: we just inserted it in `register_component_inner`
|
||||
let info = unsafe {
|
||||
&mut self
|
||||
.components
|
||||
.components
|
||||
.get_mut(id.0)
|
||||
.debug_checked_unwrap()
|
||||
.as_mut()
|
||||
.debug_checked_unwrap()
|
||||
};
|
||||
|
||||
info.hooks.update_from_component::<T>();
|
||||
|
||||
info.required_components = required_components;
|
||||
}
|
||||
|
||||
/// Registers a component described by `descriptor`.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// If this method is called multiple times with identical descriptors, a distinct [`ComponentId`]
|
||||
/// will be created for each one.
|
||||
///
|
||||
/// # See also
|
||||
///
|
||||
/// * [`Components::component_id()`]
|
||||
/// * [`ComponentsRegistrator::register_component()`]
|
||||
#[inline]
|
||||
pub fn register_component_with_descriptor(
|
||||
&mut self,
|
||||
descriptor: ComponentDescriptor,
|
||||
) -> ComponentId {
|
||||
let id = self.ids.next_mut();
|
||||
// SAFETY: The id is fresh.
|
||||
unsafe {
|
||||
self.register_component_inner(id, descriptor);
|
||||
}
|
||||
id
|
||||
}
|
||||
|
||||
/// Registers a [`Resource`] of type `T` with this instance.
|
||||
/// If a resource of this type has already been registered, this will return
|
||||
/// the ID of the pre-existing resource.
|
||||
///
|
||||
/// # See also
|
||||
///
|
||||
/// * [`Components::resource_id()`]
|
||||
/// * [`ComponentsRegistrator::register_resource_with_descriptor()`]
|
||||
#[inline]
|
||||
pub fn register_resource<T: Resource>(&mut self) -> ComponentId {
|
||||
// SAFETY: The [`ComponentDescriptor`] matches the [`TypeId`]
|
||||
unsafe {
|
||||
self.register_resource_with(TypeId::of::<T>(), || {
|
||||
ComponentDescriptor::new_resource::<T>()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Registers a [non-send resource](crate::system::NonSend) of type `T` with this instance.
|
||||
/// If a resource of this type has already been registered, this will return
|
||||
/// the ID of the pre-existing resource.
|
||||
#[inline]
|
||||
pub fn register_non_send<T: Any>(&mut self) -> ComponentId {
|
||||
// SAFETY: The [`ComponentDescriptor`] matches the [`TypeId`]
|
||||
unsafe {
|
||||
self.register_resource_with(TypeId::of::<T>(), || {
|
||||
ComponentDescriptor::new_non_send::<T>(StorageType::default())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Same as [`Components::register_resource_unchecked`] but handles safety.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The [`ComponentDescriptor`] must match the [`TypeId`].
|
||||
#[inline]
|
||||
unsafe fn register_resource_with(
|
||||
&mut self,
|
||||
type_id: TypeId,
|
||||
descriptor: impl FnOnce() -> ComponentDescriptor,
|
||||
) -> ComponentId {
|
||||
if let Some(id) = self.resource_indices.get(&type_id) {
|
||||
return *id;
|
||||
}
|
||||
|
||||
if let Some(registrator) = self
|
||||
.components
|
||||
.queued
|
||||
.get_mut()
|
||||
.unwrap_or_else(PoisonError::into_inner)
|
||||
.resources
|
||||
.remove(&type_id)
|
||||
{
|
||||
// If we are trying to register something that has already been queued, we respect the queue.
|
||||
// Just like if we are trying to register something that already is, we respect the first registration.
|
||||
return registrator.register(self);
|
||||
}
|
||||
|
||||
let id = self.ids.next_mut();
|
||||
// SAFETY: The resource is not currently registered, the id is fresh, and the [`ComponentDescriptor`] matches the [`TypeId`]
|
||||
unsafe {
|
||||
self.register_resource_unchecked(type_id, id, descriptor());
|
||||
}
|
||||
id
|
||||
}
|
||||
|
||||
/// Registers a [`Resource`] described by `descriptor`.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// If this method is called multiple times with identical descriptors, a distinct [`ComponentId`]
|
||||
/// will be created for each one.
|
||||
///
|
||||
/// # See also
|
||||
///
|
||||
/// * [`Components::resource_id()`]
|
||||
/// * [`ComponentsRegistrator::register_resource()`]
|
||||
#[inline]
|
||||
pub fn register_resource_with_descriptor(
|
||||
&mut self,
|
||||
descriptor: ComponentDescriptor,
|
||||
) -> ComponentId {
|
||||
let id = self.ids.next_mut();
|
||||
// SAFETY: The id is fresh.
|
||||
unsafe {
|
||||
self.register_component_inner(id, descriptor);
|
||||
}
|
||||
id
|
||||
}
|
||||
}
|
||||
|
||||
/// A queued component registration.
|
||||
pub(super) struct QueuedRegistration {
|
Loading…
Reference in New Issue
Block a user