diff --git a/crates/bevy_ecs/macros/src/component.rs b/crates/bevy_ecs/macros/src/component.rs index db10910e0c508..b7b7e1582c8b3 100644 --- a/crates/bevy_ecs/macros/src/component.rs +++ b/crates/bevy_ecs/macros/src/component.rs @@ -60,7 +60,7 @@ pub fn derive_component(input: TokenStream) -> TokenStream { TokenStream::from(quote! { impl #impl_generics #bevy_ecs_path::component::Component for #struct_name #type_generics #where_clause { - type Storage = #storage; + const STORAGE_TYPE: #bevy_ecs_path::component::StorageType = #storage; } }) } @@ -110,10 +110,10 @@ fn parse_component_attr(ast: &DeriveInput) -> Result { } fn storage_path(bevy_ecs_path: &Path, ty: StorageTy) -> TokenStream2 { - let typename = match ty { - StorageTy::Table => Ident::new("TableStorage", Span::call_site()), - StorageTy::SparseSet => Ident::new("SparseStorage", Span::call_site()), + let storage_type = match ty { + StorageTy::Table => Ident::new("Table", Span::call_site()), + StorageTy::SparseSet => Ident::new("SparseSet", Span::call_site()), }; - quote! { #bevy_ecs_path::component::#typename } + quote! { #bevy_ecs_path::component::StorageType::#storage_type } } diff --git a/crates/bevy_ecs/src/bundle.rs b/crates/bevy_ecs/src/bundle.rs index 2804618cbb206..f5e9a32fd0614 100644 --- a/crates/bevy_ecs/src/bundle.rs +++ b/crates/bevy_ecs/src/bundle.rs @@ -10,7 +10,7 @@ use crate::{ AddBundle, Archetype, ArchetypeId, Archetypes, BundleComponentStatus, ComponentStatus, SpawnBundleStatus, }, - component::{Component, ComponentId, ComponentStorage, Components, StorageType, Tick}, + component::{Component, ComponentId, Components, StorageType, Tick}, entity::{Entities, Entity, EntityLocation}, prelude::World, query::DebugCheckedUnwrap, @@ -203,7 +203,7 @@ unsafe impl Bundle for C { impl DynamicBundle for C { #[inline] fn get_components(self, func: &mut impl FnMut(StorageType, OwningPtr<'_>)) { - OwningPtr::make(self, |ptr| func(C::Storage::STORAGE_TYPE, ptr)); + OwningPtr::make(self, |ptr| func(C::STORAGE_TYPE, ptr)); } } diff --git a/crates/bevy_ecs/src/component.rs b/crates/bevy_ecs/src/component.rs index 74b0bf342c4b3..808fb148b5f73 100644 --- a/crates/bevy_ecs/src/component.rs +++ b/crates/bevy_ecs/src/component.rs @@ -151,42 +151,13 @@ use std::{ /// [`SyncCell`]: bevy_utils::synccell::SyncCell /// [`Exclusive`]: https://doc.rust-lang.org/nightly/std/sync/struct.Exclusive.html pub trait Component: Send + Sync + 'static { - /// A marker type indicating the storage type used for this component. - /// This must be either [`TableStorage`] or [`SparseStorage`]. - type Storage: ComponentStorage; + /// A constant indicating the storage type used for this component. + const STORAGE_TYPE: StorageType; /// Called when registering this component, allowing mutable access to it's [`ComponentHooks`]. fn register_component_hooks(_hooks: &mut ComponentHooks) {} } -/// Marker type for components stored in a [`Table`](crate::storage::Table). -pub struct TableStorage; - -/// Marker type for components stored in a [`ComponentSparseSet`](crate::storage::ComponentSparseSet). -pub struct SparseStorage; - -/// Types used to specify the storage strategy for a component. -/// -/// This trait is implemented for [`TableStorage`] and [`SparseStorage`]. -/// Custom implementations are forbidden. -pub trait ComponentStorage: sealed::Sealed { - /// A value indicating the storage strategy specified by this type. - 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 {} -} - /// The storage used for a specific component type. /// /// # Examples @@ -472,7 +443,7 @@ impl ComponentDescriptor { pub fn new() -> Self { Self { name: Cow::Borrowed(std::any::type_name::()), - storage_type: T::Storage::STORAGE_TYPE, + storage_type: T::STORAGE_TYPE, is_send_and_sync: true, type_id: Some(TypeId::of::()), layout: Layout::new::(), @@ -503,7 +474,7 @@ impl ComponentDescriptor { /// Create a new `ComponentDescriptor` for a resource. /// - /// The [`StorageType`] for resources is always [`TableStorage`]. + /// The [`StorageType`] for resources is always [`StorageType::Table`]. pub fn new_resource() -> Self { Self { name: Cow::Borrowed(std::any::type_name::()), diff --git a/crates/bevy_ecs/src/query/fetch.rs b/crates/bevy_ecs/src/query/fetch.rs index 4fb9f8a111367..7f249f4a36660 100644 --- a/crates/bevy_ecs/src/query/fetch.rs +++ b/crates/bevy_ecs/src/query/fetch.rs @@ -1,7 +1,7 @@ use crate::{ archetype::Archetype, change_detection::{Ticks, TicksMut}, - component::{Component, ComponentId, ComponentStorage, StorageType, Tick}, + component::{Component, ComponentId, StorageType, Tick}, entity::Entity, query::{Access, DebugCheckedUnwrap, FilteredAccess, WorldQuery}, storage::{ComponentSparseSet, Table, TableRow}, @@ -711,9 +711,9 @@ unsafe impl<'a> QueryData for FilteredEntityMut<'a> { #[doc(hidden)] pub struct ReadFetch<'w, T> { - // T::Storage = TableStorage + // T::STORAGE_TYPE = StorageType::Table table_components: Option>>, - // T::Storage = SparseStorage + // T::STORAGE_TYPE = StorageType::SparseSet sparse_set: Option<&'w ComponentSparseSet>, } @@ -747,7 +747,7 @@ unsafe impl WorldQuery for &T { ) -> ReadFetch<'w, T> { ReadFetch { table_components: None, - sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet).then(|| { + sparse_set: (T::STORAGE_TYPE == StorageType::SparseSet).then(|| { // SAFETY: The underlying type associated with `component_id` is `T`, // which we are allowed to access since we registered it in `update_archetype_component_access`. // Note that we do not actually access any components in this function, we just get a shared @@ -764,7 +764,7 @@ unsafe impl WorldQuery for &T { } const IS_DENSE: bool = { - match T::Storage::STORAGE_TYPE { + match T::STORAGE_TYPE { StorageType::Table => true, StorageType::SparseSet => false, } @@ -806,7 +806,7 @@ unsafe impl WorldQuery for &T { entity: Entity, table_row: TableRow, ) -> Self::Item<'w> { - match T::Storage::STORAGE_TYPE { + match T::STORAGE_TYPE { StorageType::Table => { // SAFETY: STORAGE_TYPE = Table let table = unsafe { fetch.table_components.debug_checked_unwrap() }; @@ -862,13 +862,13 @@ unsafe impl ReadOnlyQueryData for &T {} #[doc(hidden)] pub struct RefFetch<'w, T> { - // T::Storage = TableStorage + // T::STORAGE_TYPE = StorageType::Table table_data: Option<( ThinSlicePtr<'w, UnsafeCell>, ThinSlicePtr<'w, UnsafeCell>, ThinSlicePtr<'w, UnsafeCell>, )>, - // T::Storage = SparseStorage + // T::STORAGE_TYPE = StorageType::SparseSet sparse_set: Option<&'w ComponentSparseSet>, last_run: Tick, @@ -905,7 +905,7 @@ unsafe impl<'__w, T: Component> WorldQuery for Ref<'__w, T> { ) -> RefFetch<'w, T> { RefFetch { table_data: None, - sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet).then(|| { + sparse_set: (T::STORAGE_TYPE == StorageType::SparseSet).then(|| { // SAFETY: The underlying type associated with `component_id` is `T`, // which we are allowed to access since we registered it in `update_archetype_component_access`. // Note that we do not actually access any components in this function, we just get a shared @@ -924,7 +924,7 @@ unsafe impl<'__w, T: Component> WorldQuery for Ref<'__w, T> { } const IS_DENSE: bool = { - match T::Storage::STORAGE_TYPE { + match T::STORAGE_TYPE { StorageType::Table => true, StorageType::SparseSet => false, } @@ -965,7 +965,7 @@ unsafe impl<'__w, T: Component> WorldQuery for Ref<'__w, T> { entity: Entity, table_row: TableRow, ) -> Self::Item<'w> { - match T::Storage::STORAGE_TYPE { + match T::STORAGE_TYPE { StorageType::Table => { // SAFETY: STORAGE_TYPE = Table let (table_components, added_ticks, changed_ticks) = @@ -1045,13 +1045,13 @@ unsafe impl<'__w, T: Component> ReadOnlyQueryData for Ref<'__w, T> {} #[doc(hidden)] pub struct WriteFetch<'w, T> { - // T::Storage = TableStorage + // T::STORAGE_TYPE = StorageType::Table table_data: Option<( ThinSlicePtr<'w, UnsafeCell>, ThinSlicePtr<'w, UnsafeCell>, ThinSlicePtr<'w, UnsafeCell>, )>, - // T::Storage = SparseStorage + // T::STORAGE_TYPE = StorageType::SparseSet sparse_set: Option<&'w ComponentSparseSet>, last_run: Tick, @@ -1088,7 +1088,7 @@ unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T { ) -> WriteFetch<'w, T> { WriteFetch { table_data: None, - sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet).then(|| { + sparse_set: (T::STORAGE_TYPE == StorageType::SparseSet).then(|| { // SAFETY: The underlying type associated with `component_id` is `T`, // which we are allowed to access since we registered it in `update_archetype_component_access`. // Note that we do not actually access any components in this function, we just get a shared @@ -1107,7 +1107,7 @@ unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T { } const IS_DENSE: bool = { - match T::Storage::STORAGE_TYPE { + match T::STORAGE_TYPE { StorageType::Table => true, StorageType::SparseSet => false, } @@ -1148,7 +1148,7 @@ unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T { entity: Entity, table_row: TableRow, ) -> Self::Item<'w> { - match T::Storage::STORAGE_TYPE { + match T::STORAGE_TYPE { StorageType::Table => { // SAFETY: STORAGE_TYPE = Table let (table_components, added_ticks, changed_ticks) = @@ -1433,7 +1433,7 @@ unsafe impl WorldQuery for Has { } const IS_DENSE: bool = { - match T::Storage::STORAGE_TYPE { + match T::STORAGE_TYPE { StorageType::Table => true, StorageType::SparseSet => false, } diff --git a/crates/bevy_ecs/src/query/filter.rs b/crates/bevy_ecs/src/query/filter.rs index e88293e227120..cb581b58b82d6 100644 --- a/crates/bevy_ecs/src/query/filter.rs +++ b/crates/bevy_ecs/src/query/filter.rs @@ -1,6 +1,6 @@ use crate::{ archetype::Archetype, - component::{Component, ComponentId, ComponentStorage, StorageType, Tick}, + component::{Component, ComponentId, StorageType, Tick}, entity::Entity, query::{DebugCheckedUnwrap, FilteredAccess, WorldQuery}, storage::{Column, ComponentSparseSet, Table, TableRow}, @@ -142,7 +142,7 @@ unsafe impl WorldQuery for With { } const IS_DENSE: bool = { - match T::Storage::STORAGE_TYPE { + match T::STORAGE_TYPE { StorageType::Table => true, StorageType::SparseSet => false, } @@ -250,7 +250,7 @@ unsafe impl WorldQuery for Without { } const IS_DENSE: bool = { - match T::Storage::STORAGE_TYPE { + match T::STORAGE_TYPE { StorageType::Table => true, StorageType::SparseSet => false, } @@ -604,7 +604,7 @@ unsafe impl WorldQuery for Added { ) -> Self::Fetch<'w> { Self::Fetch::<'w> { table_ticks: None, - sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet) + sparse_set: (T::STORAGE_TYPE == StorageType::SparseSet) .then(|| world.storages().sparse_sets.get(id).debug_checked_unwrap()), last_run, this_run, @@ -612,7 +612,7 @@ unsafe impl WorldQuery for Added { } const IS_DENSE: bool = { - match T::Storage::STORAGE_TYPE { + match T::STORAGE_TYPE { StorageType::Table => true, StorageType::SparseSet => false, } @@ -651,7 +651,7 @@ unsafe impl WorldQuery for Added { entity: Entity, table_row: TableRow, ) -> Self::Item<'w> { - match T::Storage::STORAGE_TYPE { + match T::STORAGE_TYPE { StorageType::Table => { // SAFETY: STORAGE_TYPE = Table let table = unsafe { fetch.table_ticks.debug_checked_unwrap() }; @@ -813,7 +813,7 @@ unsafe impl WorldQuery for Changed { ) -> Self::Fetch<'w> { Self::Fetch::<'w> { table_ticks: None, - sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet) + sparse_set: (T::STORAGE_TYPE == StorageType::SparseSet) .then(|| world.storages().sparse_sets.get(id).debug_checked_unwrap()), last_run, this_run, @@ -821,7 +821,7 @@ unsafe impl WorldQuery for Changed { } const IS_DENSE: bool = { - match T::Storage::STORAGE_TYPE { + match T::STORAGE_TYPE { StorageType::Table => true, StorageType::SparseSet => false, } @@ -860,7 +860,7 @@ unsafe impl WorldQuery for Changed { entity: Entity, table_row: TableRow, ) -> Self::Item<'w> { - match T::Storage::STORAGE_TYPE { + match T::STORAGE_TYPE { StorageType::Table => { // SAFETY: STORAGE_TYPE = Table let table = unsafe { fetch.table_ticks.debug_checked_unwrap() }; diff --git a/crates/bevy_ecs/src/world/unsafe_world_cell.rs b/crates/bevy_ecs/src/world/unsafe_world_cell.rs index 977158d87cd52..9fbb6e52de668 100644 --- a/crates/bevy_ecs/src/world/unsafe_world_cell.rs +++ b/crates/bevy_ecs/src/world/unsafe_world_cell.rs @@ -7,9 +7,7 @@ use crate::{ archetype::{Archetype, ArchetypeComponentId, Archetypes}, bundle::Bundles, change_detection::{MutUntyped, Ticks, TicksMut}, - component::{ - ComponentId, ComponentStorage, ComponentTicks, Components, StorageType, Tick, TickCells, - }, + component::{ComponentId, ComponentTicks, Components, StorageType, Tick, TickCells}, entity::{Entities, Entity, EntityLocation}, prelude::Component, removal_detection::RemovedComponentEvents, @@ -713,7 +711,7 @@ impl<'w> UnsafeEntityCell<'w> { get_component( self.world, component_id, - T::Storage::STORAGE_TYPE, + T::STORAGE_TYPE, self.entity, self.location, ) @@ -740,7 +738,7 @@ impl<'w> UnsafeEntityCell<'w> { get_component_and_ticks( self.world, component_id, - T::Storage::STORAGE_TYPE, + T::STORAGE_TYPE, self.entity, self.location, ) @@ -770,7 +768,7 @@ impl<'w> UnsafeEntityCell<'w> { get_ticks( self.world, component_id, - T::Storage::STORAGE_TYPE, + T::STORAGE_TYPE, self.entity, self.location, ) @@ -839,7 +837,7 @@ impl<'w> UnsafeEntityCell<'w> { get_component_and_ticks( self.world, component_id, - T::Storage::STORAGE_TYPE, + T::STORAGE_TYPE, self.entity, self.location, ) diff --git a/examples/ecs/component_hooks.rs b/examples/ecs/component_hooks.rs index c98891bf02f3c..ae0acfefdded6 100644 --- a/examples/ecs/component_hooks.rs +++ b/examples/ecs/component_hooks.rs @@ -13,7 +13,7 @@ //! - Enforcing structural rules: When you have systems that depend on specific relationships //! between components (like hierarchies or parent-child links) and need to maintain correctness. -use bevy::ecs::component::{ComponentHooks, TableStorage}; +use bevy::ecs::component::{ComponentHooks, StorageType}; use bevy::prelude::*; use std::collections::HashMap; @@ -21,7 +21,7 @@ use std::collections::HashMap; struct MyComponent(KeyCode); impl Component for MyComponent { - type Storage = TableStorage; + const STORAGE_TYPE: StorageType = StorageType::Table; /// Hooks can also be registered during component initialisation by /// implementing `register_component_hooks`