diff --git a/crates/bevy_ecs/src/change_detection.rs b/crates/bevy_ecs/src/change_detection.rs index 3b59303de41964..46390433c8f032 100644 --- a/crates/bevy_ecs/src/change_detection.rs +++ b/crates/bevy_ecs/src/change_detection.rs @@ -1,6 +1,6 @@ //! Types that detect when their internal data mutate. -use crate::{component::ComponentTicks, system::Resource}; +use crate::{component::ComponentTicks, resource::Resource}; use bevy_reflect::Reflect; use std::ops::{Deref, DerefMut}; diff --git a/crates/bevy_ecs/src/component.rs b/crates/bevy_ecs/src/component.rs index 677766b7793cc2..b2a8133a2fb427 100644 --- a/crates/bevy_ecs/src/component.rs +++ b/crates/bevy_ecs/src/component.rs @@ -1,8 +1,8 @@ //! Types for declaring and storing [`Component`]s. use crate::{ + resource::Resource, storage::{SparseSetIndex, Storages}, - system::Resource, }; pub use bevy_ecs_macros::Component; use std::{ @@ -132,7 +132,7 @@ impl ComponentInfo { self.descriptor.is_send_and_sync } - fn new(id: ComponentId, descriptor: ComponentDescriptor) -> Self { + pub(crate) fn new(id: ComponentId, descriptor: ComponentDescriptor) -> Self { ComponentInfo { id, descriptor } } } @@ -205,7 +205,7 @@ impl ComponentDescriptor { } } - fn new_non_send(storage_type: StorageType) -> Self { + pub(crate) fn new_non_send(storage_type: StorageType) -> Self { Self { name: std::any::type_name::().to_string(), storage_type, @@ -236,7 +236,6 @@ impl ComponentDescriptor { pub struct Components { components: Vec, indices: std::collections::HashMap, - resource_indices: std::collections::HashMap, } #[derive(Debug, Error)] @@ -295,53 +294,6 @@ impl Components { 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) - } } impl<'c> IntoIterator for &'c Components { diff --git a/crates/bevy_ecs/src/event.rs b/crates/bevy_ecs/src/event.rs index d28ce5ad3ad1a6..454494ae8373fb 100644 --- a/crates/bevy_ecs/src/event.rs +++ b/crates/bevy_ecs/src/event.rs @@ -1,7 +1,7 @@ //! Event handling types. use crate::system::{Local, Res, ResMut, SystemParam}; -use crate::{self as bevy_ecs, system::Resource}; +use crate::{self as bevy_ecs, resource::Resource}; use bevy_utils::tracing::trace; use std::{ fmt::{self}, diff --git a/crates/bevy_ecs/src/lib.rs b/crates/bevy_ecs/src/lib.rs index 6fb347a2a7e8fa..7af2a79825bc52 100644 --- a/crates/bevy_ecs/src/lib.rs +++ b/crates/bevy_ecs/src/lib.rs @@ -7,6 +7,7 @@ pub mod event; pub mod query; #[cfg(feature = "bevy_reflect")] pub mod reflect; +pub mod resource; pub mod schedule; pub mod storage; pub mod system; @@ -997,7 +998,7 @@ mod tests { world.insert_resource(123); let resource_id = world - .components() + .resources() .get_resource_id(TypeId::of::()) .unwrap(); let archetype_component_id = world @@ -1062,7 +1063,7 @@ mod tests { ); let current_resource_id = world - .components() + .resources() .get_resource_id(TypeId::of::()) .unwrap(); assert_eq!( diff --git a/crates/bevy_ecs/src/resource.rs b/crates/bevy_ecs/src/resource.rs new file mode 100644 index 00000000000000..9b8b792fe4fe04 --- /dev/null +++ b/crates/bevy_ecs/src/resource.rs @@ -0,0 +1,110 @@ +//! Types for declaring and storing [`Resource`]s. + +use crate::component::{ComponentDescriptor, ComponentId, ComponentInfo, StorageType}; +use std::any::{Any, TypeId}; +use thiserror::Error; + +pub trait Resource: Send + Sync + 'static {} +impl Resource for T where T: Send + Sync + 'static {} + +#[derive(Debug, Default)] +pub struct Resources { + resources: Vec, + resource_indices: std::collections::HashMap, +} + +#[derive(Debug, Error)] +pub enum ResourceError { + #[error("A resource of type {name:?} ({type_id:?}) already exists")] + ResourceAlreadyExists { + type_id: TypeId, + name: String, + existing_id: ComponentId, + }, +} + +impl Resources { + #[inline] + pub fn len(&self) -> usize { + self.resources.len() + } + + #[inline] + pub fn is_empty(&self) -> bool { + self.resources.len() == 0 + } + + #[inline] + pub fn get_info(&self, id: ComponentId) -> Option<&ComponentInfo> { + self.resources.get(id.index()) + } + + #[inline] + pub fn get_resource_id(&self, type_id: TypeId) -> Option { + self.resource_indices + .get(&type_id) + .map(|index| ComponentId::new(*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 resources = &mut self.resources; + let index = self.resource_indices.entry(type_id).or_insert_with(|| { + let descriptor = func(); + let index = resources.len(); + resources.push(ComponentInfo::new(ComponentId::new(index), descriptor)); + index + }); + + ComponentId::new(*index) + } + + /// # Safety + /// + /// `id` must be a valid [ComponentId] + #[inline] + pub unsafe fn get_info_unchecked(&self, id: ComponentId) -> &ComponentInfo { + debug_assert!(id.index() < self.resources.len()); + self.resources.get_unchecked(id.index()) + } +} + +impl<'c> IntoIterator for &'c Resources { + type Item = &'c ComponentInfo; + + type IntoIter = std::slice::Iter<'c, ComponentInfo>; + + fn into_iter(self) -> Self::IntoIter { + self.resources.iter() + } +} + +#[cfg(test)] +mod tests {} diff --git a/crates/bevy_ecs/src/system/commands/mod.rs b/crates/bevy_ecs/src/system/commands/mod.rs index 9428b398725972..a4d16448af1b4a 100644 --- a/crates/bevy_ecs/src/system/commands/mod.rs +++ b/crates/bevy_ecs/src/system/commands/mod.rs @@ -4,14 +4,13 @@ use crate::{ bundle::Bundle, component::Component, entity::{Entities, Entity}, + resource::Resource, world::World, }; use bevy_utils::tracing::{error, warn}; pub use command_queue::CommandQueue; use std::marker::PhantomData; -use super::Resource; - /// A [`World`] mutation. pub trait Command: Send + Sync + 'static { fn write(self, world: &mut World); diff --git a/crates/bevy_ecs/src/system/mod.rs b/crates/bevy_ecs/src/system/mod.rs index a123d871b3a017..a4959bf7f9dba8 100644 --- a/crates/bevy_ecs/src/system/mod.rs +++ b/crates/bevy_ecs/src/system/mod.rs @@ -551,7 +551,7 @@ mod tests { let conflicts = x.component_access().get_conflicts(y.component_access()); let b_id = world - .components() + .resources() .get_resource_id(TypeId::of::()) .unwrap(); let d_id = world.components().get_id(TypeId::of::()).unwrap(); diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index f9f5f60794e38b..4637caec13f2e2 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -8,6 +8,7 @@ use crate::{ query::{ FilterFetch, FilteredAccess, FilteredAccessSet, QueryState, ReadOnlyFetch, WorldQuery, }, + resource::{Resource, Resources}, system::{CommandQueue, Commands, Query, SystemMeta}, world::{FromWorld, World}, }; @@ -200,9 +201,6 @@ pub struct QuerySetState(T); impl_query_set!(); -pub trait Resource: Send + Sync + 'static {} -impl Resource for T where T: Send + Sync + 'static {} - /// Shared borrow of a resource. /// /// See the [`World`] documentation to see the usage of a resource. diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index e9f56a58a8ec9a..829c898333bcbf 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -14,8 +14,8 @@ use crate::{ component::{Component, ComponentId, ComponentTicks, Components, StorageType}, entity::{AllocAtWithoutReplacement, Entities, Entity}, query::{FilterFetch, QueryState, WorldQuery}, + resource::{Resource, Resources}, storage::{Column, SparseSet, Storages}, - system::Resource, }; use std::{ any::TypeId, @@ -72,6 +72,7 @@ pub struct World { id: WorldId, pub(crate) entities: Entities, pub(crate) components: Components, + pub(crate) resources: Resources, pub(crate) archetypes: Archetypes, pub(crate) storages: Storages, pub(crate) bundles: Bundles, @@ -89,6 +90,7 @@ impl Default for World { id: WorldId::new().expect("More `bevy` `World`s have been created than is supported"), entities: Default::default(), components: Default::default(), + resources: Default::default(), archetypes: Default::default(), storages: Default::default(), bundles: Default::default(), @@ -151,6 +153,18 @@ impl World { &mut self.components } + /// Retrieves this world's [Resources] collection + #[inline] + pub fn resources(&self) -> &Resources { + &self.resources + } + + /// Retrieves a mutable reference to this world's [Resources] collection + #[inline] + pub fn resources_mut(&mut self) -> &mut Resources { + &mut self.resources + } + /// Retrieves this world's [Storages] collection #[inline] pub fn storages(&self) -> &Storages { @@ -595,7 +609,7 @@ impl World { /// Resources are "unique" data of a given type. #[inline] pub fn insert_resource(&mut self, value: T) { - let component_id = self.components.init_resource::(); + let component_id = self.resources.init_resource::(); // SAFE: component_id just initialized and corresponds to resource of type T unsafe { self.insert_resource_with_id(component_id, value) }; } @@ -605,7 +619,7 @@ impl World { #[inline] pub fn insert_non_send(&mut self, value: T) { self.validate_non_send_access::(); - let component_id = self.components.init_non_send::(); + let component_id = self.resources.init_non_send::(); // SAFE: component_id just initialized and corresponds to resource of type T unsafe { self.insert_resource_with_id(component_id, value) }; } @@ -630,7 +644,7 @@ impl World { /// make sure you're on main thread if T isn't Send + Sync #[allow(unused_unsafe)] pub unsafe fn remove_resource_unchecked(&mut self) -> Option { - let component_id = self.components.get_resource_id(TypeId::of::())?; + let component_id = self.resources.get_resource_id(TypeId::of::())?; let resource_archetype = self.archetypes.resource_mut(); let unique_components = resource_archetype.unique_components_mut(); let column = unique_components.get_mut(component_id)?; @@ -648,7 +662,7 @@ impl World { #[inline] pub fn contains_resource(&self) -> bool { let component_id = - if let Some(component_id) = self.components.get_resource_id(TypeId::of::()) { + if let Some(component_id) = self.resources.get_resource_id(TypeId::of::()) { component_id } else { return false; @@ -660,13 +674,13 @@ impl World { /// Resources are "unique" data of a given type. #[inline] pub fn get_resource(&self) -> Option<&T> { - let component_id = self.components.get_resource_id(TypeId::of::())?; + let component_id = self.resources.get_resource_id(TypeId::of::())?; unsafe { self.get_resource_with_id(component_id) } } pub fn is_resource_added(&self) -> bool { let component_id = - if let Some(component_id) = self.components.get_resource_id(TypeId::of::()) { + if let Some(component_id) = self.resources.get_resource_id(TypeId::of::()) { component_id } else { return false; @@ -683,7 +697,7 @@ impl World { pub fn is_resource_changed(&self) -> bool { let component_id = - if let Some(component_id) = self.components.get_resource_id(TypeId::of::()) { + if let Some(component_id) = self.resources.get_resource_id(TypeId::of::()) { component_id } else { return false; @@ -728,7 +742,7 @@ impl World { /// that only one mutable access exists at a time. #[inline] pub unsafe fn get_resource_unchecked_mut(&self) -> Option> { - let component_id = self.components.get_resource_id(TypeId::of::())?; + let component_id = self.resources.get_resource_id(TypeId::of::())?; self.get_resource_unchecked_mut_with_id(component_id) } @@ -736,7 +750,7 @@ impl World { /// [None] Resources are "unique" data of a given type. #[inline] pub fn get_non_send_resource(&self) -> Option<&T> { - let component_id = self.components.get_resource_id(TypeId::of::())?; + let component_id = self.resources.get_resource_id(TypeId::of::())?; // SAFE: component id matches type T unsafe { self.get_non_send_with_id(component_id) } } @@ -757,7 +771,7 @@ impl World { /// ensure that only one mutable access exists at a time. #[inline] pub unsafe fn get_non_send_resource_unchecked_mut(&self) -> Option> { - let component_id = self.components.get_resource_id(TypeId::of::())?; + let component_id = self.resources.get_resource_id(TypeId::of::())?; self.get_non_send_unchecked_mut_with_id(component_id) } @@ -909,7 +923,7 @@ impl World { /// ``` pub fn resource_scope(&mut self, f: impl FnOnce(&mut World, Mut) -> U) -> U { let component_id = self - .components + .resources .get_resource_id(TypeId::of::()) .unwrap_or_else(|| panic!("resource does not exist: {}", std::any::type_name::())); let (ptr, mut ticks) = { @@ -1029,7 +1043,7 @@ impl World { .get_unchecked_mut(ArchetypeId::RESOURCE.index()); let resource_archetype_components = &mut resource_archetype.components; let archetype_component_count = &mut self.archetypes.archetype_component_count; - let components = &self.components; + let resources = &self.resources; resource_archetype .unique_components .get_or_insert_with(component_id, || { @@ -1043,20 +1057,20 @@ impl World { }, ); *archetype_component_count += 1; - let component_info = components.get_info_unchecked(component_id); + let component_info = resources.get_info_unchecked(component_id); Column::with_capacity(component_info, 1) }) } pub(crate) fn initialize_resource(&mut self) -> ComponentId { - let component_id = self.components.init_resource::(); + let component_id = self.resources.init_resource::(); // SAFE: resource initialized above unsafe { self.initialize_resource_internal(component_id) }; component_id } pub(crate) fn initialize_non_send_resource(&mut self) -> ComponentId { - let component_id = self.components.init_non_send::(); + let component_id = self.resources.init_non_send::(); // SAFE: resource initialized above unsafe { self.initialize_resource_internal(component_id) }; component_id diff --git a/crates/bevy_ecs/src/world/world_cell.rs b/crates/bevy_ecs/src/world/world_cell.rs index e41954f394b804..1d746840ef6a5f 100644 --- a/crates/bevy_ecs/src/world/world_cell.rs +++ b/crates/bevy_ecs/src/world/world_cell.rs @@ -1,7 +1,7 @@ use crate::{ archetype::ArchetypeComponentId, + resource::Resource, storage::SparseSet, - system::Resource, world::{Mut, World}, }; use std::{ @@ -183,7 +183,7 @@ impl<'w> WorldCell<'w> { } pub fn get_resource(&self) -> Option> { - let component_id = self.world.components.get_resource_id(TypeId::of::())?; + let component_id = self.world.resources.get_resource_id(TypeId::of::())?; let resource_archetype = self.world.archetypes.resource(); let archetype_component_id = resource_archetype.get_archetype_component_id(component_id)?; Some(WorldBorrow::new( @@ -195,7 +195,7 @@ impl<'w> WorldCell<'w> { } pub fn get_resource_mut(&self) -> Option> { - let component_id = self.world.components.get_resource_id(TypeId::of::())?; + let component_id = self.world.resources.get_resource_id(TypeId::of::())?; let resource_archetype = self.world.archetypes.resource(); let archetype_component_id = resource_archetype.get_archetype_component_id(component_id)?; Some(WorldBorrowMut::new( @@ -210,7 +210,7 @@ impl<'w> WorldCell<'w> { } pub fn get_non_send(&self) -> Option> { - let component_id = self.world.components.get_resource_id(TypeId::of::())?; + let component_id = self.world.resources.get_resource_id(TypeId::of::())?; let resource_archetype = self.world.archetypes.resource(); let archetype_component_id = resource_archetype.get_archetype_component_id(component_id)?; Some(WorldBorrow::new( @@ -222,7 +222,7 @@ impl<'w> WorldCell<'w> { } pub fn get_non_send_mut(&self) -> Option> { - let component_id = self.world.components.get_resource_id(TypeId::of::())?; + let component_id = self.world.resources.get_resource_id(TypeId::of::())?; let resource_archetype = self.world.archetypes.resource(); let archetype_component_id = resource_archetype.get_archetype_component_id(component_id)?; Some(WorldBorrowMut::new( @@ -293,7 +293,7 @@ mod tests { } let u32_component_id = world - .components + .resources .get_resource_id(TypeId::of::()) .unwrap(); let resource_archetype = world.archetypes.get(ArchetypeId::RESOURCE).unwrap();