Skip to content

Commit d77ce8d

Browse files
jakobhellermannexjam
authored andcommitted
bevy_ptr standalone crate (bevyengine#4653)
# Objective The pointer types introduced in bevyengine#3001 are useful not just in `bevy_ecs`, but also in crates like `bevy_reflect` (bevyengine#4475) or even outside of bevy. ## Solution Extract `Ptr<'a>`, `PtrMut<'a>`, `OwnedPtr<'a>`, `ThinSlicePtr<'a, T>` and `UnsafeCellDeref` from `bevy_ecs::ptr` into `bevy_ptr`. **Note:** `bevy_ecs` still reexports the `bevy_ptr` as `bevy_ecs::ptr` so that crates like `bevy_transform` can use the `Bundle` derive without needing to depend on `bevy_ptr` themselves.
1 parent 06e0b06 commit d77ce8d

File tree

18 files changed

+62
-12
lines changed

18 files changed

+62
-12
lines changed

crates/bevy_ecs/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ trace = []
1414
default = ["bevy_reflect"]
1515

1616
[dependencies]
17+
bevy_ptr = { path = "../bevy_ptr", version = "0.8.0-dev" }
1718
bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", optional = true }
1819
bevy_tasks = { path = "../bevy_tasks", version = "0.8.0-dev" }
1920
bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" }

crates/bevy_ecs/src/bundle.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ use crate::{
88
archetype::{AddBundle, Archetype, ArchetypeId, Archetypes, ComponentStatus},
99
component::{Component, ComponentId, ComponentTicks, Components, StorageType},
1010
entity::{Entities, Entity, EntityLocation},
11-
ptr::OwningPtr,
1211
storage::{SparseSetIndex, SparseSets, Storages, Table},
1312
};
1413
use bevy_ecs_macros::all_tuples;
14+
use bevy_ptr::OwningPtr;
1515
use std::{any::TypeId, collections::HashMap};
1616

1717
/// An ordered collection of [`Component`]s.

crates/bevy_ecs/src/component.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
//! Types for declaring and storing [`Component`]s.
22
33
use crate::{
4-
ptr::OwningPtr,
54
storage::{SparseSetIndex, Storages},
65
system::Resource,
76
};
87
pub use bevy_ecs_macros::Component;
8+
use bevy_ptr::OwningPtr;
99
use std::{
1010
alloc::Layout,
1111
any::{Any, TypeId},

crates/bevy_ecs/src/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ pub mod change_detection;
66
pub mod component;
77
pub mod entity;
88
pub mod event;
9-
pub mod ptr;
109
pub mod query;
1110
#[cfg(feature = "bevy_reflect")]
1211
pub mod reflect;
@@ -15,6 +14,8 @@ pub mod storage;
1514
pub mod system;
1615
pub mod world;
1716

17+
pub use bevy_ptr as ptr;
18+
1819
/// Most commonly used re-exported types.
1920
pub mod prelude {
2021
#[doc(hidden)]

crates/bevy_ecs/src/query/fetch.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@ use crate::{
33
change_detection::Ticks,
44
component::{Component, ComponentId, ComponentStorage, ComponentTicks, StorageType},
55
entity::Entity,
6-
ptr::{ThinSlicePtr, UnsafeCellDeref},
76
query::{debug_checked_unreachable, Access, FilteredAccess},
87
storage::{ComponentSparseSet, Table, Tables},
98
world::{Mut, World},
109
};
1110
use bevy_ecs_macros::all_tuples;
1211
pub use bevy_ecs_macros::WorldQuery;
12+
use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref};
1313
use std::{cell::UnsafeCell, marker::PhantomData};
1414

1515
/// Types that can be queried from a [`World`].

crates/bevy_ecs/src/query/filter.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use crate::{
22
archetype::{Archetype, ArchetypeComponentId},
33
component::{Component, ComponentId, ComponentStorage, ComponentTicks, StorageType},
44
entity::Entity,
5-
ptr::{ThinSlicePtr, UnsafeCellDeref},
65
query::{
76
debug_checked_unreachable, Access, Fetch, FetchState, FilteredAccess, QueryFetch,
87
ROQueryFetch, WorldQuery, WorldQueryGats,
@@ -11,6 +10,7 @@ use crate::{
1110
world::World,
1211
};
1312
use bevy_ecs_macros::all_tuples;
13+
use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref};
1414
use std::{cell::UnsafeCell, marker::PhantomData};
1515

1616
use super::ReadOnlyFetch;

crates/bevy_ecs/src/storage/blob_vec.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::{
44
ptr::NonNull,
55
};
66

7-
use crate::ptr::{OwningPtr, Ptr, PtrMut};
7+
use bevy_ptr::{OwningPtr, Ptr, PtrMut};
88

99
/// A flat, type-erased data storage type
1010
///

crates/bevy_ecs/src/storage/sparse_set.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use crate::{
22
component::{ComponentId, ComponentInfo, ComponentTicks},
33
entity::Entity,
4-
ptr::{OwningPtr, Ptr},
54
storage::BlobVec,
65
};
6+
use bevy_ptr::{OwningPtr, Ptr};
77
use std::{cell::UnsafeCell, marker::PhantomData};
88

99
#[derive(Debug)]

crates/bevy_ecs/src/storage/table.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use crate::{
22
component::{ComponentId, ComponentInfo, ComponentTicks, Components},
33
entity::Entity,
4-
ptr::{OwningPtr, Ptr, PtrMut},
54
storage::{BlobVec, SparseSet},
65
};
6+
use bevy_ptr::{OwningPtr, Ptr, PtrMut};
77
use bevy_utils::HashMap;
88
use std::{
99
cell::UnsafeCell,

crates/bevy_ecs/src/system/system_param.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use crate::{
55
change_detection::Ticks,
66
component::{Component, ComponentId, ComponentTicks, Components},
77
entity::{Entities, Entity},
8-
ptr::UnsafeCellDeref,
98
query::{
109
Access, FilteredAccess, FilteredAccessSet, QueryFetch, QueryState, ReadOnlyFetch,
1110
WorldQuery,
@@ -15,6 +14,7 @@ use crate::{
1514
};
1615
pub use bevy_ecs_macros::SystemParam;
1716
use bevy_ecs_macros::{all_tuples, impl_param_set};
17+
use bevy_ptr::UnsafeCellDeref;
1818
use std::{
1919
fmt::Debug,
2020
marker::PhantomData,

crates/bevy_ecs/src/world/entity_ref.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ use crate::{
44
change_detection::Ticks,
55
component::{Component, ComponentId, ComponentTicks, Components, StorageType},
66
entity::{Entities, Entity, EntityLocation},
7-
ptr::{OwningPtr, Ptr, UnsafeCellDeref},
87
storage::{SparseSet, Storages},
98
world::{Mut, World},
109
};
10+
use bevy_ptr::{OwningPtr, Ptr, UnsafeCellDeref};
1111
use std::{any::TypeId, cell::UnsafeCell};
1212

1313
/// A read-only reference to a particular [`Entity`] and all of its components

crates/bevy_ecs/src/world/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ use crate::{
1313
change_detection::Ticks,
1414
component::{Component, ComponentId, ComponentTicks, Components, StorageType},
1515
entity::{AllocAtWithoutReplacement, Entities, Entity},
16-
ptr::{OwningPtr, UnsafeCellDeref},
1716
query::{QueryState, WorldQuery},
1817
storage::{Column, SparseSet, Storages},
1918
system::Resource,
2019
};
20+
use bevy_ptr::{OwningPtr, UnsafeCellDeref};
2121
use bevy_utils::tracing::debug;
2222
use std::{
2323
any::TypeId,

crates/bevy_internal/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.8.0-dev" }
7575
bevy_input = { path = "../bevy_input", version = "0.8.0-dev" }
7676
bevy_log = { path = "../bevy_log", version = "0.8.0-dev" }
7777
bevy_math = { path = "../bevy_math", version = "0.8.0-dev" }
78+
bevy_ptr = { path = "../bevy_ptr", version = "0.8.0-dev" }
7879
bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", features = ["bevy"] }
7980
bevy_scene = { path = "../bevy_scene", version = "0.8.0-dev" }
8081
bevy_transform = { path = "../bevy_transform", version = "0.8.0-dev" }

crates/bevy_internal/src/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ pub mod math {
4747
pub use bevy_math::*;
4848
}
4949

50+
pub mod ptr {
51+
//! Utilities for working with untyped pointers in a more safe way.
52+
pub use bevy_ptr::*;
53+
}
54+
5055
pub mod reflect {
5156
// TODO: remove these renames once TypeRegistryArc is no longer required
5257
//! Type reflection used for dynamically interacting with rust types.

crates/bevy_ptr/Cargo.toml

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "bevy_ptr"
3+
version = "0.8.0-dev"
4+
edition = "2021"
5+
description = "Utilities for working with untyped pointers in a more safe way"
6+
homepage = "https://bevyengine.org"
7+
repository = "https://github.com/bevyengine/bevy"
8+
license = "MIT OR Apache-2.0"
9+
keywords = ["bevy"]
10+
11+
[dependencies]

crates/bevy_ptr/README.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# `bevy_ptr`
2+
3+
The `bevy_ptr` crate provides low-level abstractions for working with pointers in a more safe way than using rust's raw pointers.
4+
5+
Rust has lifetimed and typed references (`&'a T`), unlifetimed and typed references (`*const T`), but no lifetimed but untyped references.
6+
`bevy_ptr` adds them, called `Ptr<'a>`, `PtrMut<'a>` and `OwningPtr<'a>`.
7+
These types are lifetime-checked so can never lead to problems like use-after-frees and must always point to valid data.

crates/bevy_ecs/src/ptr.rs renamed to crates/bevy_ptr/src/lib.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![doc = include_str!("../README.md")]
12
use std::{cell::UnsafeCell, marker::PhantomData, mem::MaybeUninit, ptr::NonNull};
23

34
/// Type-erased borrow of some unknown type chosen when constructing this type.
@@ -249,13 +250,35 @@ impl<'a, T> From<&'a [T]> for ThinSlicePtr<'a, T> {
249250
}
250251
}
251252

252-
pub(crate) trait UnsafeCellDeref<'a, T> {
253+
mod private {
254+
use std::cell::UnsafeCell;
255+
256+
pub trait SealedUnsafeCell {}
257+
impl<'a, T> SealedUnsafeCell for &'a UnsafeCell<T> {}
258+
}
259+
260+
/// Extension trait for helper methods on [`UnsafeCell`]
261+
pub trait UnsafeCellDeref<'a, T>: private::SealedUnsafeCell {
262+
/// # Safety
263+
/// - The returned value must be unique and not alias any mutable or immutable references to the contents of the [`UnsafeCell`].
264+
/// - 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).
253265
unsafe fn deref_mut(self) -> &'a mut T;
266+
267+
/// # Safety
268+
/// - For the lifetime `'a` of the returned value you must not construct a mutable reference to the contents of the [`UnsafeCell`].
269+
/// - 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).
254270
unsafe fn deref(self) -> &'a T;
271+
272+
/// Returns a copy of the contained value.
273+
///
274+
/// # Safety
275+
/// - The [`UnsafeCell`] must not currently have a mutable reference to its content.
276+
/// - 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).
255277
unsafe fn read(self) -> T
256278
where
257279
T: Copy;
258280
}
281+
259282
impl<'a, T> UnsafeCellDeref<'a, T> for &'a UnsafeCell<T> {
260283
#[inline]
261284
unsafe fn deref_mut(self) -> &'a mut T {

tools/publish.sh

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# if crate A depends on crate B, B must come before A in this list
22
crates=(
33
bevy_utils
4+
bevy_ptr
45
bevy_macro_utils
56
bevy_derive
67
bevy_math

0 commit comments

Comments
 (0)