1
Fork 0

Lift Pointer's requirement for the pointer to be thin

fat pointers rule!
This commit is contained in:
Maybe Waffle 2023-04-12 11:00:35 +00:00
parent 26232f1ff5
commit 9051331dd7
5 changed files with 58 additions and 33 deletions

View file

@ -0,0 +1,31 @@
use std::mem;
/// Returns the ABI-required minimum alignment of a type in bytes.
///
/// This is equivalent to [`mem::align_of`], but also works for some unsized
/// types (e.g. slices or rustc's `List`s).
pub const fn align_of<T: ?Sized + Aligned>() -> usize {
T::ALIGN
}
/// A type with a statically known alignment.
///
/// # Safety
///
/// `Self::ALIGN` must be equal to the alignment of `Self`. For sized types it
/// is [`mem::align_of<Self>()`], for unsized types it depends on the type, for
/// example `[T]` has alignment of `T`.
///
/// [`mem::align_of<Self>()`]: mem::align_of
pub unsafe trait Aligned {
/// Alignment of `Self`.
const ALIGN: usize;
}
unsafe impl<T> Aligned for T {
const ALIGN: usize = mem::align_of::<Self>();
}
unsafe impl<T> Aligned for [T] {
const ALIGN: usize = mem::align_of::<T>();
}

View file

@ -83,6 +83,7 @@ pub mod transitive_relation;
pub mod vec_linked_list;
pub mod work_queue;
pub use atomic_ref::AtomicRef;
pub mod aligned;
pub mod frozen;
pub mod owned_slice;
pub mod sso;

View file

@ -13,12 +13,14 @@
//! The tag must implement the `Tag` trait. We assert that the tag and `Pointer`
//! are compatible at compile time.
use std::mem::{self, ManuallyDrop};
use std::mem::ManuallyDrop;
use std::ops::Deref;
use std::ptr::NonNull;
use std::rc::Rc;
use std::sync::Arc;
use crate::aligned::Aligned;
mod copy;
mod drop;
@ -31,8 +33,7 @@ pub use drop::TaggedPtr;
/// # Safety
///
/// The pointer returned from [`into_ptr`] must be a [valid], pointer to
/// [`<Self as Deref>::Target`]. Note that pointers to [`Self::Target`] must be
/// thin, even though [`Self::Target`] may not be `Sized`.
/// [`<Self as Deref>::Target`].
///
/// Note that if `Self` implements [`DerefMut`] the pointer returned from
/// [`into_ptr`] must be valid for writes (and thus calling [`NonNull::as_mut`]
@ -110,7 +111,7 @@ pub unsafe trait Tag: Copy {
unsafe fn from_usize(tag: usize) -> Self;
}
unsafe impl<T> Pointer for Box<T> {
unsafe impl<T: ?Sized + Aligned> Pointer for Box<T> {
const BITS: usize = bits_for::<Self::Target>();
#[inline]
@ -130,7 +131,7 @@ unsafe impl<T> Pointer for Box<T> {
}
}
unsafe impl<T> Pointer for Rc<T> {
unsafe impl<T: ?Sized + Aligned> Pointer for Rc<T> {
const BITS: usize = bits_for::<Self::Target>();
#[inline]
@ -149,7 +150,7 @@ unsafe impl<T> Pointer for Rc<T> {
}
}
unsafe impl<T> Pointer for Arc<T> {
unsafe impl<T: ?Sized + Aligned> Pointer for Arc<T> {
const BITS: usize = bits_for::<Self::Target>();
#[inline]
@ -168,7 +169,7 @@ unsafe impl<T> Pointer for Arc<T> {
}
}
unsafe impl<'a, T: 'a> Pointer for &'a T {
unsafe impl<'a, T: 'a + ?Sized + Aligned> Pointer for &'a T {
const BITS: usize = bits_for::<Self::Target>();
#[inline]
@ -186,7 +187,7 @@ unsafe impl<'a, T: 'a> Pointer for &'a T {
}
}
unsafe impl<'a, T: 'a> Pointer for &'a mut T {
unsafe impl<'a, T: 'a + ?Sized + Aligned> Pointer for &'a mut T {
const BITS: usize = bits_for::<Self::Target>();
#[inline]
@ -206,8 +207,8 @@ unsafe impl<'a, T: 'a> Pointer for &'a mut T {
/// Returns the number of bits available for use for tags in a pointer to `T`
/// (this is based on `T`'s alignment).
pub const fn bits_for<T>() -> usize {
let bits = mem::align_of::<T>().trailing_zeros();
pub const fn bits_for<T: ?Sized + Aligned>() -> usize {
let bits = crate::aligned::align_of::<T>().trailing_zeros();
// This is a replacement for `.try_into().unwrap()` unavailable in `const`
// (it's fine to make an assert here, since this is only called in compile time)

View file

@ -55,12 +55,7 @@ where
}
const TAG_BIT_SHIFT: usize = usize::BITS as usize - T::BITS;
const ASSERTION: () = {
assert!(T::BITS <= P::BITS);
// Used for the transmute_copy's below
// TODO(waffle): do we need this assert anymore?
assert!(std::mem::size_of::<&P::Target>() == std::mem::size_of::<usize>());
};
const ASSERTION: () = { assert!(T::BITS <= P::BITS) };
/// Pack pointer `ptr` that comes from [`P::into_ptr`] with a `tag`.
///