Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

changed marker struct to const generic parameter #18086

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions crates/bevy_ecs/src/world/command_queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{
world::{DeferredWorld, World},
};
use alloc::{boxed::Box, vec::Vec};
use bevy_ptr::{OwningPtr, Unaligned};
use bevy_ptr::{OwningPtr, UNALIGNED};
use core::{
fmt::Debug,
mem::{size_of, MaybeUninit},
Expand All @@ -20,7 +20,7 @@ struct CommandMeta {
///
/// Advances `cursor` by the size of `T` in bytes.
consume_command_and_get_size:
unsafe fn(value: OwningPtr<Unaligned>, world: Option<NonNull<World>>, cursor: &mut usize),
unsafe fn(value: OwningPtr<UNALIGNED>, world: Option<NonNull<World>>, cursor: &mut usize),
}

/// Densely and efficiently stores a queue of heterogenous types implementing [`Command`].
Expand Down Expand Up @@ -249,7 +249,7 @@ impl RawCommandQueue {
// guarantees that nothing stored in the buffer will get observed after this function ends.
// `cmd` points to a valid address of a stored command, so it must be non-null.
let cmd = unsafe {
OwningPtr::<Unaligned>::new(NonNull::new_unchecked(
OwningPtr::<UNALIGNED>::new(NonNull::new_unchecked(
self.bytes.as_mut().as_mut_ptr().add(local_cursor).cast(),
))
};
Expand Down
102 changes: 45 additions & 57 deletions crates/bevy_ptr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,10 @@ use core::{
ptr::{self, NonNull},
};

/// Used as a type argument to [`Ptr`], [`PtrMut`] and [`OwningPtr`] to specify that the pointer is aligned.
#[derive(Debug, Copy, Clone)]
pub struct Aligned;

/// Used as a type argument to [`Ptr`], [`PtrMut`] and [`OwningPtr`] to specify that the pointer is not aligned.
#[derive(Debug, Copy, Clone)]
pub struct Unaligned;

/// Trait that is only implemented for [`Aligned`] and [`Unaligned`] to work around the lack of ability
/// to have const generics of an enum.
pub trait IsAligned: sealed::Sealed {}
impl IsAligned for Aligned {}
impl IsAligned for Unaligned {}

mod sealed {
pub trait Sealed {}
impl Sealed for super::Aligned {}
impl Sealed for super::Unaligned {}
}
/// Used as a const generic in [`Ptr`], [`PtrMut`], and [`OwningPtr`] to specify that the pointer is aligned.
pub const ALIGNED: bool = true;
/// Used as a const generic in [`Ptr`], [`PtrMut`], and [`OwningPtr`] to specify that the pointer is unaligned.
pub const UNALIGNED: bool = false;

/// A newtype around [`NonNull`] that only allows conversion to read-only borrows or pointers.
///
Expand Down Expand Up @@ -159,9 +144,9 @@ impl<'a, T: ?Sized> From<&'a mut T> for ConstNonNull<T> {
///
/// It may be helpful to think of this type as similar to `&'a dyn Any` but without
/// the metadata and able to point to data that does not correspond to a Rust type.
#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct Ptr<'a, A: IsAligned = Aligned>(NonNull<u8>, PhantomData<(&'a u8, A)>);
#[derive(Clone, Copy)]
pub struct Ptr<'a, const IS_ALIGNED: bool = ALIGNED>(NonNull<u8>, PhantomData<&'a u8>);

/// Type-erased mutable borrow of some unknown type chosen when constructing this type.
///
Expand All @@ -175,7 +160,7 @@ pub struct Ptr<'a, A: IsAligned = Aligned>(NonNull<u8>, PhantomData<(&'a u8, A)>
/// It may be helpful to think of this type as similar to `&'a mut dyn Any` but without
/// the metadata and able to point to data that does not correspond to a Rust type.
#[repr(transparent)]
pub struct PtrMut<'a, A: IsAligned = Aligned>(NonNull<u8>, PhantomData<(&'a mut u8, A)>);
pub struct PtrMut<'a, const IS_ALIGNED: bool = ALIGNED>(NonNull<u8>, PhantomData<&'a mut u8>);

/// Type-erased Box-like pointer to some unknown type chosen when constructing this type.
///
Expand All @@ -194,24 +179,24 @@ pub struct PtrMut<'a, A: IsAligned = Aligned>(NonNull<u8>, PhantomData<(&'a mut
/// It may be helpful to think of this type as similar to `&'a mut ManuallyDrop<dyn Any>` but
/// without the metadata and able to point to data that does not correspond to a Rust type.
#[repr(transparent)]
pub struct OwningPtr<'a, A: IsAligned = Aligned>(NonNull<u8>, PhantomData<(&'a mut u8, A)>);
pub struct OwningPtr<'a, const IS_ALIGNED: bool = ALIGNED>(NonNull<u8>, PhantomData<&'a mut u8>);

macro_rules! impl_ptr {
($ptr:ident) => {
impl<'a> $ptr<'a, Aligned> {
impl<'a> $ptr<'a, ALIGNED> {
/// Removes the alignment requirement of this pointer
pub fn to_unaligned(self) -> $ptr<'a, Unaligned> {
pub fn to_unaligned(self) -> $ptr<'a, UNALIGNED> {
$ptr(self.0, PhantomData)
}
}

impl<'a, A: IsAligned> From<$ptr<'a, A>> for NonNull<u8> {
fn from(ptr: $ptr<'a, A>) -> Self {
impl<'a, const IS_ALIGNED: bool> From<$ptr<'a, IS_ALIGNED>> for NonNull<u8> {
fn from(ptr: $ptr<'a, IS_ALIGNED>) -> Self {
ptr.0
}
}

impl<A: IsAligned> $ptr<'_, A> {
impl<const IS_ALIGNED: bool> $ptr<'_, IS_ALIGNED> {
/// Calculates the offset from a pointer.
/// As the pointer is type-erased, there is no size information available. The provided
/// `count` parameter is in raw bytes.
Expand All @@ -220,8 +205,8 @@ macro_rules! impl_ptr {
///
/// # Safety
/// - The offset cannot make the existing ptr null, or take it out of bounds for its allocation.
/// - If the `A` type parameter is [`Aligned`] then the offset must not make the resulting pointer
/// be unaligned for the pointee type.
/// - If the `IS_ALIGNED` const generic parameter is [`ALIGNED`] then the offset must not make the resulting
/// pointer be unaligned for the pointee type.
/// - The value pointed by the resulting pointer must outlive the lifetime of this pointer.
///
/// [ptr_offset]: https://doc.rust-lang.org/std/primitive.pointer.html#method.offset
Expand All @@ -242,7 +227,7 @@ macro_rules! impl_ptr {
///
/// # Safety
/// - The offset cannot make the existing ptr null, or take it out of bounds for its allocation.
/// - If the `A` type parameter is [`Aligned`] then the offset must not make the resulting pointer
/// - If the `IS_ALIGNED` const generic parameter is [`ALIGNED`] then the offset must not make the resulting pointer
/// be unaligned for the pointee type.
/// - The value pointed by the resulting pointer must outlive the lifetime of this pointer.
///
Expand All @@ -257,23 +242,26 @@ macro_rules! impl_ptr {
}
}

impl<A: IsAligned> Pointer for $ptr<'_, A> {
impl<const IS_ALIGNED: bool> Pointer for $ptr<'_, IS_ALIGNED> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Pointer::fmt(&self.0, f)
}
}

impl Debug for $ptr<'_, Aligned> {
impl<const IS_ALIGNED: bool> Debug for $ptr<'_, IS_ALIGNED> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}<Aligned>({:?})", stringify!($ptr), self.0)
}
}
impl Debug for $ptr<'_, Unaligned> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}<Unaligned>({:?})", stringify!($ptr), self.0)
write!(
f,
"{}<{}>({:?})",
stringify!($ptr),
match IS_ALIGNED {
ALIGNED => "Aligned",
UNALIGNED => "Unaligned",
},
self.0
)
}
}
};
Expand All @@ -283,12 +271,12 @@ impl_ptr!(Ptr);
impl_ptr!(PtrMut);
impl_ptr!(OwningPtr);

impl<'a, A: IsAligned> Ptr<'a, A> {
impl<'a, const IS_ALIGNED: bool> Ptr<'a, IS_ALIGNED> {
/// Creates a new instance from a raw pointer.
///
/// # Safety
/// - `inner` must point to valid value of whatever the pointee type is.
/// - If the `A` type parameter is [`Aligned`] then `inner` must be sufficiently aligned for the pointee type.
/// - If the `IS_ALIGNED` const generic parameter is [`ALIGNED`] then `inner` must be sufficiently aligned for the pointee type.
/// - `inner` must have correct provenance to allow reads of the pointee type.
/// - The lifetime `'a` must be constrained such that this [`Ptr`] will stay valid and nothing
/// can mutate the pointee while this [`Ptr`] is live except through an [`UnsafeCell`].
Expand All @@ -304,15 +292,15 @@ impl<'a, A: IsAligned> Ptr<'a, A> {
/// * There must be no active references (mutable or otherwise) to the data underlying this `Ptr`.
/// * Another [`PtrMut`] for the same [`Ptr`] must not be created until the first is dropped.
#[inline]
pub unsafe fn assert_unique(self) -> PtrMut<'a, A> {
pub unsafe fn assert_unique(self) -> PtrMut<'a, IS_ALIGNED> {
PtrMut(self.0, PhantomData)
}

/// Transforms this [`Ptr<T>`] into a `&T` with the same lifetime
///
/// # Safety
/// - `T` must be the erased pointee type for this [`Ptr`].
/// - If the type parameter `A` is [`Unaligned`] then this pointer must be sufficiently aligned
/// - If the const generic parameter `IS_ALIGNED` is [`UNALIGNED`] then this pointer must be sufficiently aligned
/// for the pointee type `T`.
#[inline]
pub unsafe fn deref<T>(self) -> &'a T {
Expand Down Expand Up @@ -340,12 +328,12 @@ impl<'a, T: ?Sized> From<&'a T> for Ptr<'a> {
}
}

impl<'a, A: IsAligned> PtrMut<'a, A> {
impl<'a, const IS_ALIGNED: bool> PtrMut<'a, IS_ALIGNED> {
/// Creates a new instance from a raw pointer.
///
/// # Safety
/// - `inner` must point to valid value of whatever the pointee type is.
/// - If the `A` type parameter is [`Aligned`] then `inner` must be sufficiently aligned for the pointee type.
/// - If the `IS_ALIGNED` const generic parameter is [`ALIGNED`] then `inner` must be sufficiently aligned for the pointee type.
/// - `inner` must have correct provenance to allow read and writes of the pointee type.
/// - The lifetime `'a` must be constrained such that this [`PtrMut`] will stay valid and nothing
/// else can read or mutate the pointee while this [`PtrMut`] is live.
Expand All @@ -359,15 +347,15 @@ impl<'a, A: IsAligned> PtrMut<'a, A> {
/// # Safety
/// Must have right to drop or move out of [`PtrMut`].
#[inline]
pub unsafe fn promote(self) -> OwningPtr<'a, A> {
pub unsafe fn promote(self) -> OwningPtr<'a, IS_ALIGNED> {
OwningPtr(self.0, PhantomData)
}

/// Transforms this [`PtrMut<T>`] into a `&mut T` with the same lifetime
///
/// # Safety
/// - `T` must be the erased pointee type for this [`PtrMut`].
/// - If the type parameter `A` is [`Unaligned`] then this pointer must be sufficiently aligned
/// - If the const generic parameter `IS_ALIGNED` is [`UNALIGNED`] then this pointer must be sufficiently aligned
/// for the pointee type `T`.
#[inline]
pub unsafe fn deref_mut<T>(self) -> &'a mut T {
Expand All @@ -387,14 +375,14 @@ impl<'a, A: IsAligned> PtrMut<'a, A> {

/// Gets a [`PtrMut`] from this with a smaller lifetime.
#[inline]
pub fn reborrow(&mut self) -> PtrMut<'_, A> {
pub fn reborrow(&mut self) -> PtrMut<'_, IS_ALIGNED> {
// SAFETY: the ptrmut we're borrowing from is assumed to be valid
unsafe { PtrMut::new(self.0) }
}

/// Gets an immutable reference from this mutable reference
#[inline]
pub fn as_ref(&self) -> Ptr<'_, A> {
pub fn as_ref(&self) -> Ptr<'_, IS_ALIGNED> {
// SAFETY: The `PtrMut` type's guarantees about the validity of this pointer are a superset of `Ptr` s guarantees
unsafe { Ptr::new(self.0) }
}
Expand Down Expand Up @@ -431,12 +419,12 @@ impl<'a> OwningPtr<'a> {
}
}

impl<'a, A: IsAligned> OwningPtr<'a, A> {
impl<'a, const IS_ALIGNED: bool> OwningPtr<'a, IS_ALIGNED> {
/// Creates a new instance from a raw pointer.
///
/// # Safety
/// - `inner` must point to valid value of whatever the pointee type is.
/// - If the `A` type parameter is [`Aligned`] then `inner` must be sufficiently aligned for the pointee type.
/// - If the `IS_ALIGNED` const generic parameter is [`ALIGNED`] then `inner` must be sufficiently aligned for the pointee type.
/// - `inner` must have correct provenance to allow read and writes of the pointee type.
/// - The lifetime `'a` must be constrained such that this [`OwningPtr`] will stay valid and nothing
/// else can read or mutate the pointee while this [`OwningPtr`] is live.
Expand All @@ -449,7 +437,7 @@ impl<'a, A: IsAligned> OwningPtr<'a, A> {
///
/// # Safety
/// - `T` must be the erased pointee type for this [`OwningPtr`].
/// - If the type parameter `A` is [`Unaligned`] then this pointer must be sufficiently aligned
/// - If the const generic parameter `IS_ALIGNED` is [`UNALIGNED`] then this pointer must be sufficiently aligned
/// for the pointee type `T`.
#[inline]
pub unsafe fn read<T>(self) -> T {
Expand All @@ -462,7 +450,7 @@ impl<'a, A: IsAligned> OwningPtr<'a, A> {
///
/// # Safety
/// - `T` must be the erased pointee type for this [`OwningPtr`].
/// - If the type parameter `A` is [`Unaligned`] then this pointer must be sufficiently aligned
/// - If the const generic parameter `IS_ALIGNED` is [`UNALIGNED`] then this pointer must be sufficiently aligned
/// for the pointee type `T`.
#[inline]
pub unsafe fn drop_as<T>(self) {
Expand All @@ -484,20 +472,20 @@ impl<'a, A: IsAligned> OwningPtr<'a, A> {

/// Gets an immutable pointer from this owned pointer.
#[inline]
pub fn as_ref(&self) -> Ptr<'_, A> {
pub fn as_ref(&self) -> Ptr<'_, IS_ALIGNED> {
// SAFETY: The `Owning` type's guarantees about the validity of this pointer are a superset of `Ptr` s guarantees
unsafe { Ptr::new(self.0) }
}

/// Gets a mutable pointer from this owned pointer.
#[inline]
pub fn as_mut(&mut self) -> PtrMut<'_, A> {
pub fn as_mut(&mut self) -> PtrMut<'_, IS_ALIGNED> {
// SAFETY: The `Owning` type's guarantees about the validity of this pointer are a superset of `Ptr` s guarantees
unsafe { PtrMut::new(self.0) }
}
}

impl<'a> OwningPtr<'a, Unaligned> {
impl<'a> OwningPtr<'a, UNALIGNED> {
/// Consumes the [`OwningPtr`] to obtain ownership of the underlying data of type `T`.
///
/// # Safety
Expand Down
4 changes: 2 additions & 2 deletions examples/ecs/dynamic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use bevy::{
world::FilteredEntityMut,
},
prelude::*,
ptr::{Aligned, OwningPtr},
ptr::{OwningPtr, ALIGNED},
};

const PROMPT: &str = "
Expand Down Expand Up @@ -196,7 +196,7 @@ fn main() {

// Constructs `OwningPtr` for each item in `components`
// By sharing the lifetime of `components` with the resulting ptrs we ensure we don't drop the data before use
fn to_owning_ptrs(components: &mut [Vec<u64>]) -> Vec<OwningPtr<Aligned>> {
fn to_owning_ptrs(components: &mut [Vec<u64>]) -> Vec<OwningPtr<ALIGNED>> {
components
.iter_mut()
.map(|data| {
Expand Down