//! Types for declaring and storing [`Component`]s. use crate::{ storage::{SparseSetIndex, Storages}, system::Resource, }; pub use bevy_ecs_macros::Component; use std::{ alloc::Layout, any::{Any, TypeId}, }; use thiserror::Error; /// A component is data associated with an [`Entity`](crate::entity::Entity). Each entity can have /// multiple different types of components, but only one of them per type. /// /// Any type that is `Send + Sync + 'static` can implement `Component` using `#[derive(Component)]`. /// /// In order to use foreign types as components, wrap them using a newtype pattern. /// ``` /// # use bevy_ecs::component::Component; /// use std::time::Duration; /// #[derive(Component)] /// struct Cooldown(Duration); /// ``` /// Components are added with new entities using [`Commands::spawn`](crate::system::Commands::spawn), /// or to existing entities with [`EntityCommands::insert`](crate::system::EntityCommands::insert), /// or their [`World`](crate::world::World) equivalents. /// /// Components can be accessed in systems by using a [`Query`](crate::system::Query) /// as one of the arguments. /// /// Components can be grouped together into a [`Bundle`](crate::bundle::Bundle). pub trait Component: Send + Sync + 'static { type Storage: ComponentStorage; } pub struct TableStorage; pub struct SparseStorage; pub trait ComponentStorage: sealed::Sealed { // because the trait is sealed, those items are private API. const STORAGE_TYPE: StorageType; } impl ComponentStorage for TableStorage { const STORAGE_TYPE: StorageType = StorageType::Table; } impl ComponentStorage for SparseStorage { const STORAGE_TYPE: StorageType = StorageType::SparseSet; } mod sealed { pub trait Sealed {} impl Sealed for super::TableStorage {} impl Sealed for super::SparseStorage {} } // ECS dependencies cannot derive Component, so we must implement it manually for relevant structs. impl Component for bevy_tasks::Task where Self: Send + Sync + 'static, { type Storage = TableStorage; } /// The storage used for a specific component type. /// /// # Examples /// The [`StorageType`] for a component is configured via the derive attribute /// /// ``` /// # use bevy_ecs::{prelude::*, component::*}; /// #[derive(Component)] /// #[component(storage = "SparseSet")] /// struct A; /// ``` #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum StorageType { /// Provides fast and cache-friendly iteration, but slower addition and removal of components. /// This is the default storage type. Table, /// Provides fast addition and removal of components, but slower iteration. SparseSet, } impl Default for StorageType { fn default() -> Self { StorageType::Table } } #[derive(Debug)] pub struct ComponentInfo { id: ComponentId, descriptor: ComponentDescriptor, } impl ComponentInfo { #[inline] pub fn id(&self) -> ComponentId { self.id } #[inline] pub fn name(&self) -> &str { &self.descriptor.name } #[inline] pub fn type_id(&self) -> Option { self.descriptor.type_id } #[inline] pub fn layout(&self) -> Layout { self.descriptor.layout } #[inline] pub fn drop(&self) -> unsafe fn(*mut u8) { self.descriptor.drop } #[inline] pub fn storage_type(&self) -> StorageType { self.descriptor.storage_type } #[inline] pub fn is_send_and_sync(&self) -> bool { self.descriptor.is_send_and_sync } fn new(id: ComponentId, descriptor: ComponentDescriptor) -> Self { ComponentInfo { id, descriptor } } } #[derive(Debug, Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)] pub struct ComponentId(usize); impl ComponentId { #[inline] pub const fn new(index: usize) -> ComponentId { ComponentId(index) } #[inline] pub fn index(self) -> usize { self.0 } } impl SparseSetIndex for ComponentId { #[inline] fn sparse_set_index(&self) -> usize { self.index() } fn get_sparse_set_index(value: usize) -> Self { Self(value) } } #[derive(Debug)] pub struct ComponentDescriptor { name: String, // SAFETY: This must remain private. It must match the statically known StorageType of the // associated rust component type if one exists. storage_type: StorageType, // SAFETY: This must remain private. It must only be set to "true" if this component is // actually Send + Sync is_send_and_sync: bool, type_id: Option, layout: Layout, drop: unsafe fn(*mut u8), } impl ComponentDescriptor { // SAFETY: The pointer points to a valid value of type `T` and it is safe to drop this value. unsafe fn drop_ptr(x: *mut u8) { x.cast::().drop_in_place() } pub fn new() -> Self { Self { name: std::any::type_name::().to_string(), storage_type: T::Storage::STORAGE_TYPE, is_send_and_sync: true, type_id: Some(TypeId::of::()), layout: Layout::new::(), drop: Self::drop_ptr::, } } pub fn new_resource(storage_type: StorageType) -> Self { Self { name: std::any::type_name::().to_string(), storage_type, is_send_and_sync: true, type_id: Some(TypeId::of::()), layout: Layout::new::(), drop: Self::drop_ptr::, } } fn new_non_send(storage_type: StorageType) -> Self { Self { name: std::any::type_name::().to_string(), storage_type, is_send_and_sync: false, type_id: Some(TypeId::of::()), layout: Layout::new::(), drop: Self::drop_ptr::, } } #[inline] pub fn storage_type(&self) -> StorageType { self.storage_type } #[inline] pub fn type_id(&self) -> Option { self.type_id } #[inline] pub fn name(&self) -> &str { &self.name } } #[derive(Debug, Default)] pub struct Components { components: Vec, indices: std::collections::HashMap, resource_indices: std::collections::HashMap, } #[derive(Debug, Error)] pub enum ComponentsError { #[error("A component of type {name:?} ({type_id:?}) already exists")] ComponentAlreadyExists { type_id: TypeId, name: String, existing_id: ComponentId, }, } impl Components { #[inline] pub fn init_component(&mut self, storages: &mut Storages) -> ComponentId { let type_id = TypeId::of::(); let components = &mut self.components; let index = self.indices.entry(type_id).or_insert_with(|| { let index = components.len(); let descriptor = ComponentDescriptor::new::(); let info = ComponentInfo::new(ComponentId(index), descriptor); if T::Storage::STORAGE_TYPE == StorageType::SparseSet { storages.sparse_sets.get_or_insert(&info); } components.push(info); index }); ComponentId(*index) } #[inline] pub fn len(&self) -> usize { self.components.len() } #[inline] pub fn is_empty(&self) -> bool { self.components.len() == 0 } #[inline] pub fn get_info(&self, id: ComponentId) -> Option<&ComponentInfo> { self.components.get(id.0) } /// # Safety /// /// `id` must be a valid [ComponentId] #[inline] pub unsafe fn get_info_unchecked(&self, id: ComponentId) -> &ComponentInfo { debug_assert!(id.index() < self.components.len()); self.components.get_unchecked(id.0) } #[inline] pub fn get_id(&self, type_id: TypeId) -> Option { self.indices.get(&type_id).map(|index| ComponentId(*index)) } #[inline] pub fn get_resource_id(&self, type_id: TypeId) -> Option { self.resource_indices .get(&type_id) .map(|index| ComponentId(*index)) } #[inline] pub fn init_resource(&mut self) -> ComponentId { // SAFE: The [`ComponentDescriptor`] matches the [`TypeId`] unsafe { self.get_or_insert_resource_with(TypeId::of::(), || { ComponentDescriptor::new_resource::(StorageType::default()) }) } } #[inline] pub fn init_non_send(&mut self) -> ComponentId { // SAFE: The [`ComponentDescriptor`] matches the [`TypeId`] unsafe { self.get_or_insert_resource_with(TypeId::of::(), || { ComponentDescriptor::new_non_send::(StorageType::default()) }) } } /// # Safety /// /// The [`ComponentDescriptor`] must match the [`TypeId`] #[inline] unsafe fn get_or_insert_resource_with( &mut self, type_id: TypeId, func: impl FnOnce() -> ComponentDescriptor, ) -> ComponentId { let components = &mut self.components; let index = self.resource_indices.entry(type_id).or_insert_with(|| { let descriptor = func(); let index = components.len(); components.push(ComponentInfo::new(ComponentId(index), descriptor)); index }); ComponentId(*index) } } #[derive(Clone, Debug)] pub struct ComponentTicks { pub(crate) added: u32, pub(crate) changed: u32, } impl ComponentTicks { #[inline] pub fn is_added(&self, last_change_tick: u32, change_tick: u32) -> bool { // The comparison is relative to `change_tick` so that we can detect changes over the whole // `u32` range. Comparing directly the ticks would limit to half that due to overflow // handling. let component_delta = change_tick.wrapping_sub(self.added); let system_delta = change_tick.wrapping_sub(last_change_tick); component_delta < system_delta } #[inline] pub fn is_changed(&self, last_change_tick: u32, change_tick: u32) -> bool { let component_delta = change_tick.wrapping_sub(self.changed); let system_delta = change_tick.wrapping_sub(last_change_tick); component_delta < system_delta } pub(crate) fn new(change_tick: u32) -> Self { Self { added: change_tick, changed: change_tick, } } pub(crate) fn check_ticks(&mut self, change_tick: u32) { check_tick(&mut self.added, change_tick); check_tick(&mut self.changed, change_tick); } /// Manually sets the change tick. /// Usually, this is done automatically via the [`DerefMut`](std::ops::DerefMut) implementation /// on [`Mut`](crate::world::Mut) or [`ResMut`](crate::system::ResMut) etc. /// /// # Example /// ```rust,no_run /// # use bevy_ecs::{world::World, component::ComponentTicks}; /// let world: World = unimplemented!(); /// let component_ticks: ComponentTicks = unimplemented!(); /// /// component_ticks.set_changed(world.read_change_tick()); /// ``` #[inline] pub fn set_changed(&mut self, change_tick: u32) { self.changed = change_tick; } } fn check_tick(last_change_tick: &mut u32, change_tick: u32) { let tick_delta = change_tick.wrapping_sub(*last_change_tick); const MAX_DELTA: u32 = (u32::MAX / 4) * 3; // Clamp to max delta if tick_delta > MAX_DELTA { *last_change_tick = change_tick.wrapping_sub(MAX_DELTA); } }