From 46f69241f008dcbacc9b6c89dd985b5f2a5842b3 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Fri, 31 Mar 2023 16:53:18 -0400 Subject: [PATCH 01/14] add a type for interior mutable world storages --- crates/bevy_ecs/src/storage/mod.rs | 57 +++++++++++++++++++ .../bevy_ecs/src/world/unsafe_world_cell.rs | 12 +++- 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/storage/mod.rs b/crates/bevy_ecs/src/storage/mod.rs index 2cabf44303040..b1ffb0325b6a2 100644 --- a/crates/bevy_ecs/src/storage/mod.rs +++ b/crates/bevy_ecs/src/storage/mod.rs @@ -29,6 +29,8 @@ pub use resource::*; pub use sparse_set::*; pub use table::*; +use crate::component::ComponentId; + /// The raw data stores of a [World](crate::world::World) #[derive(Default)] pub struct Storages { @@ -41,3 +43,58 @@ pub struct Storages { /// Backing storage for `!Send` resources. pub non_send_resources: Resources, } + +/// Provides interior-mutable access to a world's internal data storages. +/// +/// Any instance of this type is associated with a set of world data that +/// it is allowed to access. This should be described in the documentation +/// of wherever you obtained the `UnsafeStorages`. +/// +/// For instance, if you originally obtained it from a system running on +/// a multi-threaded executor, then you are only allowed to access data +/// that has been registered in the system's `archetype_component_access`. +/// If you originally obtained an `UnsafeStorages` from an `&World`, +/// then you have read-only access to the entire world. +/// +/// Accessing world data that do not have access to, or mutably accessing +/// data that you only have read-access to, is considered undefined behavior. +pub struct UnsafeStorages<'a> { + pub sparse_sets: UnsafeSparseSets<'a>, + pub tables: UnsafeTables<'a>, + pub resources: UnsafeResources<'a, true>, + pub non_send_resources: UnsafeResources<'a, false>, +} + +impl<'a> UnsafeStorages<'a> { + pub(crate) fn new(storages: &'a Storages) -> Self { + Self { + sparse_sets: UnsafeSparseSets { + sparse_sets: &storages.sparse_sets, + }, + tables: UnsafeTables { + tables: &storages.tables, + }, + resources: UnsafeResources { + resources: &storages.resources, + }, + non_send_resources: UnsafeResources { + resources: &storages.non_send_resources, + }, + } + } +} + +#[derive(Clone, Copy)] +pub struct UnsafeSparseSets<'a> { + sparse_sets: &'a SparseSets, +} + +#[derive(Clone, Copy)] +pub struct UnsafeTables<'a> { + tables: &'a Tables, +} + +#[derive(Clone, Copy)] +pub struct UnsafeResources<'a, const SEND: bool> { + resources: &'a Resources, +} diff --git a/crates/bevy_ecs/src/world/unsafe_world_cell.rs b/crates/bevy_ecs/src/world/unsafe_world_cell.rs index 99231fe3f32ef..c0882a44ec0fe 100644 --- a/crates/bevy_ecs/src/world/unsafe_world_cell.rs +++ b/crates/bevy_ecs/src/world/unsafe_world_cell.rs @@ -10,7 +10,7 @@ use crate::{ }, entity::{Entities, Entity, EntityLocation}, prelude::Component, - storage::{Column, ComponentSparseSet}, + storage::{Column, ComponentSparseSet, UnsafeStorages}, system::Resource, }; use bevy_ptr::Ptr; @@ -151,6 +151,16 @@ impl<'w> UnsafeWorldCell<'w> { unsafe { &*self.0 } } + /// Returns interior-mutable access to the world's internal data stores. + /// The returned [`UnsafeStorages`] can only be used to access data + /// that this `UnsafeWorldCell` has permission to access. + pub fn storages(self) -> UnsafeStorages<'w> { + // SAFETY: Interior mutable access to the world is hidden behind + // `UnsafeStorages`, which will require any data access to be valid. + let storages = unsafe { self.unsafe_world().storages() }; + UnsafeStorages::new(storages) + } + /// Retrieves this world's [Entities] collection #[inline] pub fn entities(self) -> &'w Entities { From 561416a6600fb5487563a86ac8f73417aaff5a87 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Fri, 31 Mar 2023 17:05:21 -0400 Subject: [PATCH 02/14] add types for unsafely accessing individual data stores --- crates/bevy_ecs/src/storage/mod.rs | 15 ++++++++++++--- crates/bevy_ecs/src/storage/resource.rs | 17 +++++++++++++++++ crates/bevy_ecs/src/storage/sparse_set.rs | 19 +++++++++++++++++++ crates/bevy_ecs/src/storage/table.rs | 20 ++++++++++++++++++++ 4 files changed, 68 insertions(+), 3 deletions(-) diff --git a/crates/bevy_ecs/src/storage/mod.rs b/crates/bevy_ecs/src/storage/mod.rs index b1ffb0325b6a2..550e6136cc696 100644 --- a/crates/bevy_ecs/src/storage/mod.rs +++ b/crates/bevy_ecs/src/storage/mod.rs @@ -89,12 +89,21 @@ pub struct UnsafeSparseSets<'a> { sparse_sets: &'a SparseSets, } +impl<'a> UnsafeSparseSets<'a> { + pub fn get(self, component_id: ComponentId) -> Option> { + self.sparse_sets + .get(component_id) + .map(|sparse_set| UnsafeComponentSparseSet { sparse_set }) + } +} + #[derive(Clone, Copy)] pub struct UnsafeTables<'a> { tables: &'a Tables, } -#[derive(Clone, Copy)] -pub struct UnsafeResources<'a, const SEND: bool> { - resources: &'a Resources, +impl<'a> UnsafeTables<'a> { + pub fn get(self, id: TableId) -> Option> { + self.tables.get(id).map(|table| UnsafeTable { table }) + } } diff --git a/crates/bevy_ecs/src/storage/resource.rs b/crates/bevy_ecs/src/storage/resource.rs index f856bf9bb791d..1b0ce190c267d 100644 --- a/crates/bevy_ecs/src/storage/resource.rs +++ b/crates/bevy_ecs/src/storage/resource.rs @@ -286,3 +286,20 @@ impl Resources { } } } + +#[derive(Clone, Copy)] +pub struct UnsafeResources<'a, const SEND: bool> { + pub(super) resources: &'a Resources, +} + +impl<'a, const SEND: bool> UnsafeResources<'a, SEND> { + /// Returns the entity's component and associated ticks. + /// + /// # Safety + /// + /// The [`UnsafeWorldCell`] that this instance was obtained from + /// must be allowed to read the resource associated with `component_id`. + pub unsafe fn get(self, component_id: ComponentId) -> Option<&'a ResourceData> { + self.resources.get(component_id) + } +} diff --git a/crates/bevy_ecs/src/storage/sparse_set.rs b/crates/bevy_ecs/src/storage/sparse_set.rs index d15aca7c4ae84..cb62ba864d076 100644 --- a/crates/bevy_ecs/src/storage/sparse_set.rs +++ b/crates/bevy_ecs/src/storage/sparse_set.rs @@ -626,6 +626,25 @@ impl SparseSets { } } +#[derive(Clone, Copy)] +pub struct UnsafeComponentSparseSet<'a> { + pub(super) sparse_set: &'a ComponentSparseSet, +} + +impl<'a> UnsafeComponentSparseSet<'a> { + /// Returns the entity's component and associated ticks. + /// + /// # Safety + /// + /// The [`UnsafeStorages`]) that this instance was obtained from + /// must be allowed to read `entity`'s component from this sparse set. + /// + /// [`UnsafeStorages`]: super::UnsafeStorages + pub unsafe fn get(self, entity: Entity) -> Option<(Ptr<'a>, TickCells<'a>)> { + self.sparse_set.get_with_ticks(entity) + } +} + #[cfg(test)] mod tests { use super::SparseSets; diff --git a/crates/bevy_ecs/src/storage/table.rs b/crates/bevy_ecs/src/storage/table.rs index bae50e86c22a4..656a2cd8c58ed 100644 --- a/crates/bevy_ecs/src/storage/table.rs +++ b/crates/bevy_ecs/src/storage/table.rs @@ -909,6 +909,26 @@ impl IndexMut for Tables { } } +#[derive(Clone, Copy)] +pub struct UnsafeTable<'a> { + pub(super) table: &'a Table, +} + +impl<'a> UnsafeTable<'a> { + /// Gets access to the data for a specific component in this table. + /// + /// # Safety + /// + /// The [`UnsafeStorages`]) that this instance was obtained from + /// must be allowed to access the data associated with `component_id` + /// in this table's archetype. + /// + /// [`UnsafeStorages`]: super::UnsafeStorages + pub unsafe fn get_column(self, component_id: ComponentId) -> Option<&'a Column> { + self.table.get_column(component_id) + } +} + #[cfg(test)] mod tests { use crate as bevy_ecs; From 577d0d252b9a583d3fd469d674dee55db6be40f4 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Fri, 31 Mar 2023 17:40:47 -0400 Subject: [PATCH 03/14] add a method for safely accessing table metadata --- crates/bevy_ecs/src/storage/table.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/storage/table.rs b/crates/bevy_ecs/src/storage/table.rs index 656a2cd8c58ed..6e07467988f29 100644 --- a/crates/bevy_ecs/src/storage/table.rs +++ b/crates/bevy_ecs/src/storage/table.rs @@ -559,7 +559,7 @@ pub struct Table { } impl Table { - /// Fetches a read-only slice of the entities stored within the [`Table`]. + /// Returns the entities stored in this table. #[inline] pub fn entities(&self) -> &[Entity] { &self.entities @@ -927,6 +927,17 @@ impl<'a> UnsafeTable<'a> { pub unsafe fn get_column(self, component_id: ComponentId) -> Option<&'a Column> { self.table.get_column(component_id) } + + /// Returns `true` if this table has a column associated with `component_id`. + /// Otherwise, this returns `false`. + pub fn has_column(self, component_id: ComponentId) -> bool { + self.table.has_column(component_id) + } + + /// Returns the entities stored in this table. + pub fn entities(self) -> &'a [Entity] { + self.table.entities() + } } #[cfg(test)] From a9402225b244befd011677ffb99a58f4751480aa Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Fri, 31 Mar 2023 17:41:13 -0400 Subject: [PATCH 04/14] add functions for accessing individual sparse set component ticks --- crates/bevy_ecs/src/storage/sparse_set.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/crates/bevy_ecs/src/storage/sparse_set.rs b/crates/bevy_ecs/src/storage/sparse_set.rs index cb62ba864d076..6c8572325e677 100644 --- a/crates/bevy_ecs/src/storage/sparse_set.rs +++ b/crates/bevy_ecs/src/storage/sparse_set.rs @@ -643,6 +643,26 @@ impl<'a> UnsafeComponentSparseSet<'a> { pub unsafe fn get(self, entity: Entity) -> Option<(Ptr<'a>, TickCells<'a>)> { self.sparse_set.get_with_ticks(entity) } + + /// If `entity` has a component in this sparse set, returns the tick + /// indicating when it was added. + /// + /// Before dereferencing this, take care to ensure that the instance + /// of [`UnsafeStorages`] that this `UnsafeComponentSparseSet` was + /// obtained from has permission to access this component's data. + pub fn get_added_tick(self, entity: Entity) -> Option<&'a UnsafeCell> { + self.sparse_set.get_added_ticks(entity) + } + + /// If `entity` has a component in this sparse set, returns the tick + /// indicating when it was last changed. + /// + /// Before dereferencing this, take care to ensure that the instance + /// of [`UnsafeStorages`] that this `UnsafeComponentSparseSet` was + /// obtained from has permission to access this component's data. + pub fn get_changed_tick(self, entity: Entity) -> Option<&'a UnsafeCell> { + self.sparse_set.get_changed_ticks(entity) + } } #[cfg(test)] From 4c2afb4ecf9bf7d958c61b044b6de7e06272541f Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Fri, 31 Mar 2023 19:39:26 -0400 Subject: [PATCH 05/14] add docs to structs --- crates/bevy_ecs/src/storage/mod.rs | 2 ++ crates/bevy_ecs/src/storage/resource.rs | 3 +++ crates/bevy_ecs/src/storage/sparse_set.rs | 3 +++ crates/bevy_ecs/src/storage/table.rs | 3 +++ 4 files changed, 11 insertions(+) diff --git a/crates/bevy_ecs/src/storage/mod.rs b/crates/bevy_ecs/src/storage/mod.rs index 550e6136cc696..87f5bbe3a8809 100644 --- a/crates/bevy_ecs/src/storage/mod.rs +++ b/crates/bevy_ecs/src/storage/mod.rs @@ -84,6 +84,7 @@ impl<'a> UnsafeStorages<'a> { } } +/// A view into the [`ComponentSparseSet`] collection of [`UnsafeStorages`]. #[derive(Clone, Copy)] pub struct UnsafeSparseSets<'a> { sparse_sets: &'a SparseSets, @@ -97,6 +98,7 @@ impl<'a> UnsafeSparseSets<'a> { } } +/// A view into the [`Table`] collection of [`UnsafeStorages`]. #[derive(Clone, Copy)] pub struct UnsafeTables<'a> { tables: &'a Tables, diff --git a/crates/bevy_ecs/src/storage/resource.rs b/crates/bevy_ecs/src/storage/resource.rs index 1b0ce190c267d..54c711d683bac 100644 --- a/crates/bevy_ecs/src/storage/resource.rs +++ b/crates/bevy_ecs/src/storage/resource.rs @@ -287,6 +287,9 @@ impl Resources { } } +/// A view into a [`Resources`] collection of [`UnsafeStorages`]. +/// +/// [`UnsafeStorages`]: super::UnsafeStorages #[derive(Clone, Copy)] pub struct UnsafeResources<'a, const SEND: bool> { pub(super) resources: &'a Resources, diff --git a/crates/bevy_ecs/src/storage/sparse_set.rs b/crates/bevy_ecs/src/storage/sparse_set.rs index 6c8572325e677..54abdc9314656 100644 --- a/crates/bevy_ecs/src/storage/sparse_set.rs +++ b/crates/bevy_ecs/src/storage/sparse_set.rs @@ -626,6 +626,9 @@ impl SparseSets { } } +/// A view into a [`ComponentSparseSet`] from [`UnsafeStorages`]. +/// +/// [`UnsafeStorages`]: super::UnsafeStorages #[derive(Clone, Copy)] pub struct UnsafeComponentSparseSet<'a> { pub(super) sparse_set: &'a ComponentSparseSet, diff --git a/crates/bevy_ecs/src/storage/table.rs b/crates/bevy_ecs/src/storage/table.rs index 6e07467988f29..596531a35d5a9 100644 --- a/crates/bevy_ecs/src/storage/table.rs +++ b/crates/bevy_ecs/src/storage/table.rs @@ -909,6 +909,9 @@ impl IndexMut for Tables { } } +/// A view into a [`Table`] from [`UnsafeStorages`]. +/// +/// [`UnsafeStorages`]: super::UnsafeStorages #[derive(Clone, Copy)] pub struct UnsafeTable<'a> { pub(super) table: &'a Table, From 4e98fb9ef3be8650b6d6cd649a1b78c6f0b7bd3c Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Fri, 31 Mar 2023 20:09:53 -0400 Subject: [PATCH 06/14] make safety comments consisent with `UnsafeWorldCell` --- crates/bevy_ecs/src/storage/resource.rs | 6 ++++-- crates/bevy_ecs/src/storage/sparse_set.rs | 9 +++++---- crates/bevy_ecs/src/storage/table.rs | 11 ++++++----- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/crates/bevy_ecs/src/storage/resource.rs b/crates/bevy_ecs/src/storage/resource.rs index 54c711d683bac..f518c0b3ffaac 100644 --- a/crates/bevy_ecs/src/storage/resource.rs +++ b/crates/bevy_ecs/src/storage/resource.rs @@ -299,9 +299,11 @@ impl<'a, const SEND: bool> UnsafeResources<'a, SEND> { /// Returns the entity's component and associated ticks. /// /// # Safety + /// It is the callers responsibility to ensure that + /// - the [`UnsafeWorldCell`] self as obtained from has permission to access the resource mutably + /// - no mutable reference to the resource exists at the same time /// - /// The [`UnsafeWorldCell`] that this instance was obtained from - /// must be allowed to read the resource associated with `component_id`. + /// [`UnsafeWorldCell`]: crate::world::unsafe_world_cell::UnsafeWorldCell pub unsafe fn get(self, component_id: ComponentId) -> Option<&'a ResourceData> { self.resources.get(component_id) } diff --git a/crates/bevy_ecs/src/storage/sparse_set.rs b/crates/bevy_ecs/src/storage/sparse_set.rs index 54abdc9314656..923fe822ed01f 100644 --- a/crates/bevy_ecs/src/storage/sparse_set.rs +++ b/crates/bevy_ecs/src/storage/sparse_set.rs @@ -638,11 +638,12 @@ impl<'a> UnsafeComponentSparseSet<'a> { /// Returns the entity's component and associated ticks. /// /// # Safety + /// It is the callers responsibility to ensure that + /// - the [`UnsafeWorldCell`] self was obtianed from has permission + /// to access the component. + /// - no other mutable references to the component exist at the same time. /// - /// The [`UnsafeStorages`]) that this instance was obtained from - /// must be allowed to read `entity`'s component from this sparse set. - /// - /// [`UnsafeStorages`]: super::UnsafeStorages + /// [`UnsafeWorldCell`]: crate::world::unsafe_world_cell::UnsafeWorldCell pub unsafe fn get(self, entity: Entity) -> Option<(Ptr<'a>, TickCells<'a>)> { self.sparse_set.get_with_ticks(entity) } diff --git a/crates/bevy_ecs/src/storage/table.rs b/crates/bevy_ecs/src/storage/table.rs index 596531a35d5a9..fa1f864b093f5 100644 --- a/crates/bevy_ecs/src/storage/table.rs +++ b/crates/bevy_ecs/src/storage/table.rs @@ -921,12 +921,13 @@ impl<'a> UnsafeTable<'a> { /// Gets access to the data for a specific component in this table. /// /// # Safety + /// It is the callers responsibility to ensure that + /// - the [`UnsafeWorldCell`] self was obtained from has permission + /// to access the component in this table's archetype. + /// - no other mutable references to components of this type + /// exist in this table at the same time. /// - /// The [`UnsafeStorages`]) that this instance was obtained from - /// must be allowed to access the data associated with `component_id` - /// in this table's archetype. - /// - /// [`UnsafeStorages`]: super::UnsafeStorages + /// [`UnsafeWorldCell`]: crate::world::unsafe_world_cell::UnsafeWorldCell pub unsafe fn get_column(self, component_id: ComponentId) -> Option<&'a Column> { self.table.get_column(component_id) } From cb79f9349378e1b6974af39decd5e1f54b0165d5 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Fri, 31 Mar 2023 20:14:22 -0400 Subject: [PATCH 07/14] tweak phrasing of `entities` --- crates/bevy_ecs/src/storage/table.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ecs/src/storage/table.rs b/crates/bevy_ecs/src/storage/table.rs index fa1f864b093f5..2ff186b2858a3 100644 --- a/crates/bevy_ecs/src/storage/table.rs +++ b/crates/bevy_ecs/src/storage/table.rs @@ -559,7 +559,7 @@ pub struct Table { } impl Table { - /// Returns the entities stored in this table. + /// Returns the entities with components stored in this table. #[inline] pub fn entities(&self) -> &[Entity] { &self.entities @@ -938,7 +938,7 @@ impl<'a> UnsafeTable<'a> { self.table.has_column(component_id) } - /// Returns the entities stored in this table. + /// Returns the entities with components stored in this table. pub fn entities(self) -> &'a [Entity] { self.table.entities() } From 310e5df549a845575a17205a947920aa9b3edb21 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Fri, 31 Mar 2023 20:15:34 -0400 Subject: [PATCH 08/14] use consistent docs for `has_column` --- crates/bevy_ecs/src/storage/table.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ecs/src/storage/table.rs b/crates/bevy_ecs/src/storage/table.rs index 2ff186b2858a3..a9cc339dbc739 100644 --- a/crates/bevy_ecs/src/storage/table.rs +++ b/crates/bevy_ecs/src/storage/table.rs @@ -932,8 +932,11 @@ impl<'a> UnsafeTable<'a> { self.table.get_column(component_id) } - /// Returns `true` if this table has a column associated with `component_id`. - /// Otherwise, this returns `false`. + /// Checks if the table contains a [`Column`] for a given [`Component`]. + /// + /// Returns `true` if the column is present, `false` otherwise. + /// + /// [`Component`]: crate::component::Component pub fn has_column(self, component_id: ComponentId) -> bool { self.table.has_column(component_id) } From e84704a9a8c4380a91de73c129d94b3299e08a14 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Fri, 31 Mar 2023 20:16:02 -0400 Subject: [PATCH 09/14] add a word --- crates/bevy_ecs/src/storage/table.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/storage/table.rs b/crates/bevy_ecs/src/storage/table.rs index a9cc339dbc739..b46f00f0e7893 100644 --- a/crates/bevy_ecs/src/storage/table.rs +++ b/crates/bevy_ecs/src/storage/table.rs @@ -918,7 +918,7 @@ pub struct UnsafeTable<'a> { } impl<'a> UnsafeTable<'a> { - /// Gets access to the data for a specific component in this table. + /// Gets access to the data for a specific component type in this table. /// /// # Safety /// It is the callers responsibility to ensure that From 52683ed8dd914fc273d6f5654b11c91277f3482c Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Fri, 31 Mar 2023 20:22:40 -0400 Subject: [PATCH 10/14] add docs to high-level `get` functions --- crates/bevy_ecs/src/storage/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/bevy_ecs/src/storage/mod.rs b/crates/bevy_ecs/src/storage/mod.rs index 87f5bbe3a8809..7f858e860df83 100644 --- a/crates/bevy_ecs/src/storage/mod.rs +++ b/crates/bevy_ecs/src/storage/mod.rs @@ -91,6 +91,7 @@ pub struct UnsafeSparseSets<'a> { } impl<'a> UnsafeSparseSets<'a> { + /// Gets a view into the [`ComponentSparseSet`] associated with `component_id`. pub fn get(self, component_id: ComponentId) -> Option> { self.sparse_sets .get(component_id) @@ -105,6 +106,7 @@ pub struct UnsafeTables<'a> { } impl<'a> UnsafeTables<'a> { + /// Gets a view into the [`Table`] associated with `id`. pub fn get(self, id: TableId) -> Option> { self.tables.get(id).map(|table| UnsafeTable { table }) } From 0c7df0dde506c5581bb65d80150badf7a28d0b09 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Fri, 31 Mar 2023 20:42:21 -0400 Subject: [PATCH 11/14] resolve links --- crates/bevy_ecs/src/storage/sparse_set.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/bevy_ecs/src/storage/sparse_set.rs b/crates/bevy_ecs/src/storage/sparse_set.rs index 923fe822ed01f..2a7d7dbc63db8 100644 --- a/crates/bevy_ecs/src/storage/sparse_set.rs +++ b/crates/bevy_ecs/src/storage/sparse_set.rs @@ -654,6 +654,8 @@ impl<'a> UnsafeComponentSparseSet<'a> { /// Before dereferencing this, take care to ensure that the instance /// of [`UnsafeStorages`] that this `UnsafeComponentSparseSet` was /// obtained from has permission to access this component's data. + /// + /// [`UnsafeStorages`]: super::UnsafeStorages pub fn get_added_tick(self, entity: Entity) -> Option<&'a UnsafeCell> { self.sparse_set.get_added_ticks(entity) } @@ -664,6 +666,8 @@ impl<'a> UnsafeComponentSparseSet<'a> { /// Before dereferencing this, take care to ensure that the instance /// of [`UnsafeStorages`] that this `UnsafeComponentSparseSet` was /// obtained from has permission to access this component's data. + /// + /// [`UnsafeStorages`]: super::UnsafeStorages pub fn get_changed_tick(self, entity: Entity) -> Option<&'a UnsafeCell> { self.sparse_set.get_changed_ticks(entity) } From bf614134fa314cd5e7ca9c26e5e5a1a71909e434 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Fri, 31 Mar 2023 21:12:42 -0400 Subject: [PATCH 12/14] fix resources docs --- crates/bevy_ecs/src/storage/resource.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/storage/resource.rs b/crates/bevy_ecs/src/storage/resource.rs index f518c0b3ffaac..5753de6a72f89 100644 --- a/crates/bevy_ecs/src/storage/resource.rs +++ b/crates/bevy_ecs/src/storage/resource.rs @@ -296,7 +296,7 @@ pub struct UnsafeResources<'a, const SEND: bool> { } impl<'a, const SEND: bool> UnsafeResources<'a, SEND> { - /// Returns the entity's component and associated ticks. + /// Gets access to the resource's data store, if it is registered. /// /// # Safety /// It is the callers responsibility to ensure that From 507683123f6c914cb45b2f26a9122e68b86e44a4 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Sat, 1 Apr 2023 08:30:13 -0400 Subject: [PATCH 13/14] update documentation for `Option`-returning fns --- crates/bevy_ecs/src/storage/mod.rs | 5 +++-- crates/bevy_ecs/src/storage/sparse_set.rs | 3 ++- crates/bevy_ecs/src/storage/table.rs | 3 ++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/crates/bevy_ecs/src/storage/mod.rs b/crates/bevy_ecs/src/storage/mod.rs index 7f858e860df83..cf11955a5cbb8 100644 --- a/crates/bevy_ecs/src/storage/mod.rs +++ b/crates/bevy_ecs/src/storage/mod.rs @@ -91,7 +91,8 @@ pub struct UnsafeSparseSets<'a> { } impl<'a> UnsafeSparseSets<'a> { - /// Gets a view into the [`ComponentSparseSet`] associated with `component_id`. + /// Gets a view into the [`ComponentSparseSet`] associated with `component_id`, + /// if one exists. pub fn get(self, component_id: ComponentId) -> Option> { self.sparse_sets .get(component_id) @@ -106,7 +107,7 @@ pub struct UnsafeTables<'a> { } impl<'a> UnsafeTables<'a> { - /// Gets a view into the [`Table`] associated with `id`. + /// Gets a view into the [`Table`] associated with `id`, if one exists. pub fn get(self, id: TableId) -> Option> { self.tables.get(id).map(|table| UnsafeTable { table }) } diff --git a/crates/bevy_ecs/src/storage/sparse_set.rs b/crates/bevy_ecs/src/storage/sparse_set.rs index 2a7d7dbc63db8..50798222189fe 100644 --- a/crates/bevy_ecs/src/storage/sparse_set.rs +++ b/crates/bevy_ecs/src/storage/sparse_set.rs @@ -635,7 +635,8 @@ pub struct UnsafeComponentSparseSet<'a> { } impl<'a> UnsafeComponentSparseSet<'a> { - /// Returns the entity's component and associated ticks. + /// If `entity` has a component stored in this sparse set, + /// returns the component's value and associated change [`Tick`]s. /// /// # Safety /// It is the callers responsibility to ensure that diff --git a/crates/bevy_ecs/src/storage/table.rs b/crates/bevy_ecs/src/storage/table.rs index b46f00f0e7893..3727a4e0adea9 100644 --- a/crates/bevy_ecs/src/storage/table.rs +++ b/crates/bevy_ecs/src/storage/table.rs @@ -918,7 +918,8 @@ pub struct UnsafeTable<'a> { } impl<'a> UnsafeTable<'a> { - /// Gets access to the data for a specific component type in this table. + /// If this table stores components of type `component_id`, + /// gets access to the [`Column`] storing those components. /// /// # Safety /// It is the callers responsibility to ensure that From 47801ef98c2a4c2576e169e79e4d3d127112e630 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Wed, 10 May 2023 17:07:27 -0400 Subject: [PATCH 14/14] simplify `UnsafeStorages` --- crates/bevy_ecs/src/storage/mod.rs | 74 ++++++++++++------------- crates/bevy_ecs/src/storage/resource.rs | 22 -------- 2 files changed, 34 insertions(+), 62 deletions(-) diff --git a/crates/bevy_ecs/src/storage/mod.rs b/crates/bevy_ecs/src/storage/mod.rs index cf11955a5cbb8..1097840428aa7 100644 --- a/crates/bevy_ecs/src/storage/mod.rs +++ b/crates/bevy_ecs/src/storage/mod.rs @@ -58,57 +58,51 @@ pub struct Storages { /// /// Accessing world data that do not have access to, or mutably accessing /// data that you only have read-access to, is considered undefined behavior. -pub struct UnsafeStorages<'a> { - pub sparse_sets: UnsafeSparseSets<'a>, - pub tables: UnsafeTables<'a>, - pub resources: UnsafeResources<'a, true>, - pub non_send_resources: UnsafeResources<'a, false>, -} +pub struct UnsafeStorages<'a>(&'a Storages); impl<'a> UnsafeStorages<'a> { pub(crate) fn new(storages: &'a Storages) -> Self { - Self { - sparse_sets: UnsafeSparseSets { - sparse_sets: &storages.sparse_sets, - }, - tables: UnsafeTables { - tables: &storages.tables, - }, - resources: UnsafeResources { - resources: &storages.resources, - }, - non_send_resources: UnsafeResources { - resources: &storages.non_send_resources, - }, - } + Self(storages) } -} - -/// A view into the [`ComponentSparseSet`] collection of [`UnsafeStorages`]. -#[derive(Clone, Copy)] -pub struct UnsafeSparseSets<'a> { - sparse_sets: &'a SparseSets, -} -impl<'a> UnsafeSparseSets<'a> { /// Gets a view into the [`ComponentSparseSet`] associated with `component_id`, /// if one exists. - pub fn get(self, component_id: ComponentId) -> Option> { - self.sparse_sets + pub fn get_sparse_set(self, component_id: ComponentId) -> Option> { + self.0 + .sparse_sets .get(component_id) .map(|sparse_set| UnsafeComponentSparseSet { sparse_set }) } -} -/// A view into the [`Table`] collection of [`UnsafeStorages`]. -#[derive(Clone, Copy)] -pub struct UnsafeTables<'a> { - tables: &'a Tables, -} - -impl<'a> UnsafeTables<'a> { /// Gets a view into the [`Table`] associated with `id`, if one exists. - pub fn get(self, id: TableId) -> Option> { - self.tables.get(id).map(|table| UnsafeTable { table }) + pub fn get_table(self, id: TableId) -> Option> { + self.0.tables.get(id).map(|table| UnsafeTable { table }) + } + + /// Gets access to the resource's data store, if it is registered. + /// + /// # Safety + /// It is the callers responsibility to ensure that + /// - the [`UnsafeWorldCell`] that self was obtained from has permission to access the resource + /// - no mutable reference to the resource exists at the same time + /// + /// [`UnsafeWorldCell`]: crate::world::unsafe_world_cell::UnsafeWorldCell + pub unsafe fn get_resource(self, component_id: ComponentId) -> Option<&'a ResourceData> { + self.0.resources.get(component_id) + } + + /// Gets access to the specified non-send resource's data store, if it is registered. + /// + /// # Safety + /// It is the callers responsibility to ensure that + /// - the [`UnsafeWorldCell`] that self was obtained from has permission to access the resource + /// - no mutable reference to the resource exists at the same time + /// + /// [`UnsafeWorldCell`]: crate::world::unsafe_world_cell::UnsafeWorldCell + pub unsafe fn get_non_send_resource( + self, + component_id: ComponentId, + ) -> Option<&'a ResourceData> { + self.0.non_send_resources.get(component_id) } } diff --git a/crates/bevy_ecs/src/storage/resource.rs b/crates/bevy_ecs/src/storage/resource.rs index 5753de6a72f89..f856bf9bb791d 100644 --- a/crates/bevy_ecs/src/storage/resource.rs +++ b/crates/bevy_ecs/src/storage/resource.rs @@ -286,25 +286,3 @@ impl Resources { } } } - -/// A view into a [`Resources`] collection of [`UnsafeStorages`]. -/// -/// [`UnsafeStorages`]: super::UnsafeStorages -#[derive(Clone, Copy)] -pub struct UnsafeResources<'a, const SEND: bool> { - pub(super) resources: &'a Resources, -} - -impl<'a, const SEND: bool> UnsafeResources<'a, SEND> { - /// Gets access to the resource's data store, if it is registered. - /// - /// # Safety - /// It is the callers responsibility to ensure that - /// - the [`UnsafeWorldCell`] self as obtained from has permission to access the resource mutably - /// - no mutable reference to the resource exists at the same time - /// - /// [`UnsafeWorldCell`]: crate::world::unsafe_world_cell::UnsafeWorldCell - pub unsafe fn get(self, component_id: ComponentId) -> Option<&'a ResourceData> { - self.resources.get(component_id) - } -}