From 53f8925df7aabd178ee641efdd04055fa2157075 Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Wed, 4 May 2022 10:08:50 +0200 Subject: [PATCH 1/9] move ptr types from bevy_ecs to bevy_ptr --- crates/bevy_ecs/Cargo.toml | 1 + crates/bevy_ecs/src/bundle.rs | 2 +- crates/bevy_ecs/src/component.rs | 2 +- crates/bevy_ecs/src/lib.rs | 1 - crates/bevy_ecs/src/query/fetch.rs | 2 +- crates/bevy_ecs/src/query/filter.rs | 2 +- crates/bevy_ecs/src/storage/blob_vec.rs | 2 +- crates/bevy_ecs/src/storage/sparse_set.rs | 2 +- crates/bevy_ecs/src/storage/table.rs | 2 +- crates/bevy_ecs/src/system/system_param.rs | 2 +- crates/bevy_ecs/src/world/entity_ref.rs | 2 +- crates/bevy_ecs/src/world/mod.rs | 2 +- crates/bevy_ptr/Cargo.toml | 11 +++++++++++ crates/{bevy_ecs/src/ptr.rs => bevy_ptr/src/lib.rs} | 0 14 files changed, 22 insertions(+), 11 deletions(-) create mode 100644 crates/bevy_ptr/Cargo.toml rename crates/{bevy_ecs/src/ptr.rs => bevy_ptr/src/lib.rs} (100%) diff --git a/crates/bevy_ecs/Cargo.toml b/crates/bevy_ecs/Cargo.toml index c7a76ac02bdf7..7262c85c9f491 100644 --- a/crates/bevy_ecs/Cargo.toml +++ b/crates/bevy_ecs/Cargo.toml @@ -14,6 +14,7 @@ trace = [] default = ["bevy_reflect"] [dependencies] +bevy_ptr = { path = "../bevy_ptr", version = "0.8.0-dev" } bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", optional = true } bevy_tasks = { path = "../bevy_tasks", version = "0.8.0-dev" } bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } diff --git a/crates/bevy_ecs/src/bundle.rs b/crates/bevy_ecs/src/bundle.rs index 1fa9fa9653112..1ff332ec62ca6 100644 --- a/crates/bevy_ecs/src/bundle.rs +++ b/crates/bevy_ecs/src/bundle.rs @@ -8,10 +8,10 @@ use crate::{ archetype::{AddBundle, Archetype, ArchetypeId, Archetypes, ComponentStatus}, component::{Component, ComponentId, ComponentTicks, Components, StorageType}, entity::{Entities, Entity, EntityLocation}, - ptr::OwningPtr, storage::{SparseSetIndex, SparseSets, Storages, Table}, }; use bevy_ecs_macros::all_tuples; +use bevy_ptr::OwningPtr; use std::{any::TypeId, collections::HashMap}; /// An ordered collection of [`Component`]s. diff --git a/crates/bevy_ecs/src/component.rs b/crates/bevy_ecs/src/component.rs index fac3bfb9dbeff..92767386742c7 100644 --- a/crates/bevy_ecs/src/component.rs +++ b/crates/bevy_ecs/src/component.rs @@ -1,11 +1,11 @@ //! Types for declaring and storing [`Component`]s. use crate::{ - ptr::OwningPtr, storage::{SparseSetIndex, Storages}, system::Resource, }; pub use bevy_ecs_macros::Component; +use bevy_ptr::OwningPtr; use std::{ alloc::Layout, any::{Any, TypeId}, diff --git a/crates/bevy_ecs/src/lib.rs b/crates/bevy_ecs/src/lib.rs index 6cbfabdaeac20..43e392e2bf27c 100644 --- a/crates/bevy_ecs/src/lib.rs +++ b/crates/bevy_ecs/src/lib.rs @@ -6,7 +6,6 @@ pub mod change_detection; pub mod component; pub mod entity; pub mod event; -pub mod ptr; pub mod query; #[cfg(feature = "bevy_reflect")] pub mod reflect; diff --git a/crates/bevy_ecs/src/query/fetch.rs b/crates/bevy_ecs/src/query/fetch.rs index 9a6ad81fb02e9..5a89bc5280f63 100644 --- a/crates/bevy_ecs/src/query/fetch.rs +++ b/crates/bevy_ecs/src/query/fetch.rs @@ -3,13 +3,13 @@ use crate::{ change_detection::Ticks, component::{Component, ComponentId, ComponentStorage, ComponentTicks, StorageType}, entity::Entity, - ptr::{ThinSlicePtr, UnsafeCellDeref}, query::{debug_checked_unreachable, Access, FilteredAccess}, storage::{ComponentSparseSet, Table, Tables}, world::{Mut, World}, }; use bevy_ecs_macros::all_tuples; pub use bevy_ecs_macros::WorldQuery; +use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref}; use std::{cell::UnsafeCell, marker::PhantomData}; /// Types that can be queried from a [`World`]. diff --git a/crates/bevy_ecs/src/query/filter.rs b/crates/bevy_ecs/src/query/filter.rs index ab0aa8dd03ada..276b43459e64d 100644 --- a/crates/bevy_ecs/src/query/filter.rs +++ b/crates/bevy_ecs/src/query/filter.rs @@ -2,7 +2,6 @@ use crate::{ archetype::{Archetype, ArchetypeComponentId}, component::{Component, ComponentId, ComponentStorage, ComponentTicks, StorageType}, entity::Entity, - ptr::{ThinSlicePtr, UnsafeCellDeref}, query::{ debug_checked_unreachable, Access, Fetch, FetchState, FilteredAccess, QueryFetch, ROQueryFetch, WorldQuery, WorldQueryGats, @@ -11,6 +10,7 @@ use crate::{ world::World, }; use bevy_ecs_macros::all_tuples; +use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref}; use std::{cell::UnsafeCell, marker::PhantomData}; use super::ReadOnlyFetch; diff --git a/crates/bevy_ecs/src/storage/blob_vec.rs b/crates/bevy_ecs/src/storage/blob_vec.rs index f46ab409e4cfb..c2902553e7124 100644 --- a/crates/bevy_ecs/src/storage/blob_vec.rs +++ b/crates/bevy_ecs/src/storage/blob_vec.rs @@ -4,7 +4,7 @@ use std::{ ptr::NonNull, }; -use crate::ptr::{OwningPtr, Ptr, PtrMut}; +use bevy_ptr::{OwningPtr, Ptr, PtrMut}; /// A flat, type-erased data storage type /// diff --git a/crates/bevy_ecs/src/storage/sparse_set.rs b/crates/bevy_ecs/src/storage/sparse_set.rs index 3a2c8d3675ea4..192cfd2aae9bc 100644 --- a/crates/bevy_ecs/src/storage/sparse_set.rs +++ b/crates/bevy_ecs/src/storage/sparse_set.rs @@ -1,9 +1,9 @@ use crate::{ component::{ComponentId, ComponentInfo, ComponentTicks}, entity::Entity, - ptr::{OwningPtr, Ptr}, storage::BlobVec, }; +use bevy_ptr::{OwningPtr, Ptr}; use std::{cell::UnsafeCell, marker::PhantomData}; #[derive(Debug)] diff --git a/crates/bevy_ecs/src/storage/table.rs b/crates/bevy_ecs/src/storage/table.rs index 21884dd3ab729..755644998decf 100644 --- a/crates/bevy_ecs/src/storage/table.rs +++ b/crates/bevy_ecs/src/storage/table.rs @@ -1,9 +1,9 @@ use crate::{ component::{ComponentId, ComponentInfo, ComponentTicks, Components}, entity::Entity, - ptr::{OwningPtr, Ptr, PtrMut}, storage::{BlobVec, SparseSet}, }; +use bevy_ptr::{OwningPtr, Ptr, PtrMut}; use bevy_utils::HashMap; use std::{ cell::UnsafeCell, diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index e86b0d12abb68..55cb02176a5ab 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -5,7 +5,6 @@ use crate::{ change_detection::Ticks, component::{Component, ComponentId, ComponentTicks, Components}, entity::{Entities, Entity}, - ptr::UnsafeCellDeref, query::{ Access, FilteredAccess, FilteredAccessSet, QueryFetch, QueryState, ReadOnlyFetch, WorldQuery, @@ -15,6 +14,7 @@ use crate::{ }; pub use bevy_ecs_macros::SystemParam; use bevy_ecs_macros::{all_tuples, impl_param_set}; +use bevy_ptr::UnsafeCellDeref; use std::{ fmt::Debug, marker::PhantomData, diff --git a/crates/bevy_ecs/src/world/entity_ref.rs b/crates/bevy_ecs/src/world/entity_ref.rs index 9a53fe8992b6c..c9b6006381a7d 100644 --- a/crates/bevy_ecs/src/world/entity_ref.rs +++ b/crates/bevy_ecs/src/world/entity_ref.rs @@ -4,10 +4,10 @@ use crate::{ change_detection::Ticks, component::{Component, ComponentId, ComponentTicks, Components, StorageType}, entity::{Entities, Entity, EntityLocation}, - ptr::{OwningPtr, Ptr, UnsafeCellDeref}, storage::{SparseSet, Storages}, world::{Mut, World}, }; +use bevy_ptr::{OwningPtr, Ptr, UnsafeCellDeref}; use std::{any::TypeId, cell::UnsafeCell}; /// A read-only reference to a particular [`Entity`] and all of its components diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index bd71cefddd8b6..bdcd809bd9e23 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -13,11 +13,11 @@ use crate::{ change_detection::Ticks, component::{Component, ComponentId, ComponentTicks, Components, StorageType}, entity::{AllocAtWithoutReplacement, Entities, Entity}, - ptr::{OwningPtr, UnsafeCellDeref}, query::{QueryState, WorldQuery}, storage::{Column, SparseSet, Storages}, system::Resource, }; +use bevy_ptr::{OwningPtr, UnsafeCellDeref}; use bevy_utils::tracing::debug; use std::{ any::TypeId, diff --git a/crates/bevy_ptr/Cargo.toml b/crates/bevy_ptr/Cargo.toml new file mode 100644 index 0000000000000..12e1b2edddde3 --- /dev/null +++ b/crates/bevy_ptr/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "bevy_ptr" +version = "0.8.0-dev" +edition = "2021" +description = "Bevy Engine's entity component system" +homepage = "https://bevyengine.org" +repository = "https://github.com/bevyengine/bevy" +license = "MIT OR Apache-2.0" +keywords = ["bevy"] + +[dependencies] diff --git a/crates/bevy_ecs/src/ptr.rs b/crates/bevy_ptr/src/lib.rs similarity index 100% rename from crates/bevy_ecs/src/ptr.rs rename to crates/bevy_ptr/src/lib.rs From 81cbe5784450070560e6636a661d3bce6625716f Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Wed, 4 May 2022 10:14:21 +0200 Subject: [PATCH 2/9] reexport bevy_ptr as bevy_ecs::ptr to fix Bundle derive --- crates/bevy_ecs/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/bevy_ecs/src/lib.rs b/crates/bevy_ecs/src/lib.rs index 43e392e2bf27c..15a5ac64a8d22 100644 --- a/crates/bevy_ecs/src/lib.rs +++ b/crates/bevy_ecs/src/lib.rs @@ -14,6 +14,8 @@ pub mod storage; pub mod system; pub mod world; +pub use bevy_ptr as ptr; + /// Most commonly used re-exported types. pub mod prelude { #[doc(hidden)] From 5edf6270ed006e5fc5f7af306027c51047d6a06e Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Wed, 4 May 2022 10:10:41 +0200 Subject: [PATCH 3/9] make UnsafeCellDeref pub --- crates/bevy_ptr/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ptr/src/lib.rs b/crates/bevy_ptr/src/lib.rs index 2f81e4632b376..3bd68bf3703c4 100644 --- a/crates/bevy_ptr/src/lib.rs +++ b/crates/bevy_ptr/src/lib.rs @@ -249,7 +249,7 @@ impl<'a, T> From<&'a [T]> for ThinSlicePtr<'a, T> { } } -pub(crate) trait UnsafeCellDeref<'a, T> { +pub trait UnsafeCellDeref<'a, T> { unsafe fn deref_mut(self) -> &'a mut T; unsafe fn deref(self) -> &'a T; unsafe fn read(self) -> T From c2a9d2791b3e6f21e7ba68d1d200227788d4fc2c Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Wed, 4 May 2022 10:19:50 +0200 Subject: [PATCH 4/9] add bevy::ptr --- crates/bevy_internal/Cargo.toml | 1 + crates/bevy_internal/src/lib.rs | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/crates/bevy_internal/Cargo.toml b/crates/bevy_internal/Cargo.toml index 360c957e984bc..35be208d1ba6d 100644 --- a/crates/bevy_internal/Cargo.toml +++ b/crates/bevy_internal/Cargo.toml @@ -75,6 +75,7 @@ bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.8.0-dev" } bevy_input = { path = "../bevy_input", version = "0.8.0-dev" } bevy_log = { path = "../bevy_log", version = "0.8.0-dev" } bevy_math = { path = "../bevy_math", version = "0.8.0-dev" } +bevy_ptr = { path = "../bevy_ptr", version = "0.8.0-dev" } bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", features = ["bevy"] } bevy_scene = { path = "../bevy_scene", version = "0.8.0-dev" } bevy_transform = { path = "../bevy_transform", version = "0.8.0-dev" } diff --git a/crates/bevy_internal/src/lib.rs b/crates/bevy_internal/src/lib.rs index a6992073137cd..95d1cb35e234c 100644 --- a/crates/bevy_internal/src/lib.rs +++ b/crates/bevy_internal/src/lib.rs @@ -47,6 +47,11 @@ pub mod math { pub use bevy_math::*; } +pub mod ptr { + //! Utilities for working with untyped pointers in a more safe way. + pub use bevy_ptr::*; +} + pub mod reflect { // TODO: remove these renames once TypeRegistryArc is no longer required //! Type reflection used for dynamically interacting with rust types. From ca5f5970a126f06821be987ea5bb39f1fa4b75a1 Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Wed, 4 May 2022 10:43:31 +0200 Subject: [PATCH 5/9] add doc comments to UnsafeCellDeref and seal the trait --- crates/bevy_ptr/src/lib.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ptr/src/lib.rs b/crates/bevy_ptr/src/lib.rs index 3bd68bf3703c4..82ea254248dfb 100644 --- a/crates/bevy_ptr/src/lib.rs +++ b/crates/bevy_ptr/src/lib.rs @@ -249,13 +249,35 @@ impl<'a, T> From<&'a [T]> for ThinSlicePtr<'a, T> { } } -pub trait UnsafeCellDeref<'a, T> { +mod private { + use std::cell::UnsafeCell; + + pub trait SealedUnsafeCell {} + impl<'a, T> SealedUnsafeCell for &'a UnsafeCell {} +} + +/// Extension trait for helper methods on [`UnsafeCell`] +pub trait UnsafeCellDeref<'a, T>: private::SealedUnsafeCell { + /// # Safety + /// - The returned value must be unique and not alias any mutable or immutable references to the contents of the [`UnsafeCell`]. + /// - At all times, you must avoid data races. If multiple threads have access to the same UnsafeCell, then any writes must have a proper happens-before relation to all other accesses or use atomics ([`UnsafeCell`] docs for reference). unsafe fn deref_mut(self) -> &'a mut T; + + /// # Safety + /// - For the lifetime `'a` of the returned value you must not construct a mutable reference to the contents of the [`UnsafeCell`]. + /// - At all times, you must avoid data races. If multiple threads have access to the same UnsafeCell, then any writes must have a proper happens-before relation to all other accesses or use atomics ([`UnsafeCell`] docs for reference). unsafe fn deref(self) -> &'a T; + + /// Returns a copy of the contained value. + /// + /// # Safety + /// - The [`UnsafeCell`] must not currently have a mutable reference to its content. + /// - At all times, you must avoid data races. If multiple threads have access to the same UnsafeCell, then any writes must have a proper happens-before relation to all other accesses or use atomics ([`UnsafeCell`] docs for reference). unsafe fn read(self) -> T where T: Copy; } + impl<'a, T> UnsafeCellDeref<'a, T> for &'a UnsafeCell { #[inline] unsafe fn deref_mut(self) -> &'a mut T { From bd189f1b59c49ea93dbd0407ff4f41f86942dbae Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Wed, 4 May 2022 11:02:28 +0200 Subject: [PATCH 6/9] add some crate-level docs/README --- crates/bevy_ptr/README.md | 7 +++++++ crates/bevy_ptr/src/lib.rs | 1 + 2 files changed, 8 insertions(+) create mode 100644 crates/bevy_ptr/README.md diff --git a/crates/bevy_ptr/README.md b/crates/bevy_ptr/README.md new file mode 100644 index 0000000000000..a08c3043ec391 --- /dev/null +++ b/crates/bevy_ptr/README.md @@ -0,0 +1,7 @@ +# `bevy_ptr` + +The `bevy_ptr` crate provides low-level abstractions for working with pointers in a more safe way than using rust's raw pointers. + +Rust has lifetimed and typed references (`&'a T`), unlifetimed and typed references (`*const T`), but no lifetimed but untyped references. +`bevy_ptr` adds them, called `Ptr<'a>`, `PtrMut<'a>` and `OwningPtr<'a>`. +These types are lifetime-checked so can never lead to problems like use-after-frees and must always point to valid data. diff --git a/crates/bevy_ptr/src/lib.rs b/crates/bevy_ptr/src/lib.rs index 82ea254248dfb..2f3f7a19e8695 100644 --- a/crates/bevy_ptr/src/lib.rs +++ b/crates/bevy_ptr/src/lib.rs @@ -1,3 +1,4 @@ +#![doc = include_str!("../README.md")] use std::{cell::UnsafeCell, marker::PhantomData, mem::MaybeUninit, ptr::NonNull}; /// Type-erased borrow of some unknown type chosen when constructing this type. From 3c6540b16b4d9108835310757aaeb9e28e9fe2a5 Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Wed, 4 May 2022 11:13:08 +0200 Subject: [PATCH 7/9] fix clippy --- crates/bevy_ptr/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/bevy_ptr/src/lib.rs b/crates/bevy_ptr/src/lib.rs index 2f3f7a19e8695..cb3cc2abb3c39 100644 --- a/crates/bevy_ptr/src/lib.rs +++ b/crates/bevy_ptr/src/lib.rs @@ -261,19 +261,19 @@ mod private { pub trait UnsafeCellDeref<'a, T>: private::SealedUnsafeCell { /// # Safety /// - The returned value must be unique and not alias any mutable or immutable references to the contents of the [`UnsafeCell`]. - /// - At all times, you must avoid data races. If multiple threads have access to the same UnsafeCell, then any writes must have a proper happens-before relation to all other accesses or use atomics ([`UnsafeCell`] docs for reference). + /// - At all times, you must avoid data races. If multiple threads have access to the same [`UnsafeCell`], then any writes must have a proper happens-before relation to all other accesses or use atomics ([`UnsafeCell`] docs for reference). unsafe fn deref_mut(self) -> &'a mut T; /// # Safety /// - For the lifetime `'a` of the returned value you must not construct a mutable reference to the contents of the [`UnsafeCell`]. - /// - At all times, you must avoid data races. If multiple threads have access to the same UnsafeCell, then any writes must have a proper happens-before relation to all other accesses or use atomics ([`UnsafeCell`] docs for reference). + /// - At all times, you must avoid data races. If multiple threads have access to the same [`UnsafeCell`], then any writes must have a proper happens-before relation to all other accesses or use atomics ([`UnsafeCell`] docs for reference). unsafe fn deref(self) -> &'a T; /// Returns a copy of the contained value. /// /// # Safety /// - The [`UnsafeCell`] must not currently have a mutable reference to its content. - /// - At all times, you must avoid data races. If multiple threads have access to the same UnsafeCell, then any writes must have a proper happens-before relation to all other accesses or use atomics ([`UnsafeCell`] docs for reference). + /// - At all times, you must avoid data races. If multiple threads have access to the same [`UnsafeCell`], then any writes must have a proper happens-before relation to all other accesses or use atomics ([`UnsafeCell`] docs for reference). unsafe fn read(self) -> T where T: Copy; From cdaab243b8ac629176052e2dc7d3ac10db86516e Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Wed, 4 May 2022 11:24:55 +0200 Subject: [PATCH 8/9] fix bevy_ptr Cargo.toml description --- crates/bevy_ptr/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ptr/Cargo.toml b/crates/bevy_ptr/Cargo.toml index 12e1b2edddde3..0b3d02daab8e5 100644 --- a/crates/bevy_ptr/Cargo.toml +++ b/crates/bevy_ptr/Cargo.toml @@ -2,7 +2,7 @@ name = "bevy_ptr" version = "0.8.0-dev" edition = "2021" -description = "Bevy Engine's entity component system" +description = "Utilities for working with untyped pointers in a more safe way" homepage = "https://bevyengine.org" repository = "https://github.com/bevyengine/bevy" license = "MIT OR Apache-2.0" From cc3665c59eaf14f01137fd9f2e00b7b51c8a8479 Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Wed, 4 May 2022 11:40:23 +0200 Subject: [PATCH 9/9] add bevy_ptr to tools/publish.sh --- tools/publish.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/publish.sh b/tools/publish.sh index 67b17c3ab0492..124e63d0dc726 100644 --- a/tools/publish.sh +++ b/tools/publish.sh @@ -1,6 +1,7 @@ # if crate A depends on crate B, B must come before A in this list crates=( bevy_utils + bevy_ptr bevy_macro_utils bevy_derive bevy_math