Skip to content

Commit

Permalink
[wip] UnalignUnsized
Browse files Browse the repository at this point in the history
  • Loading branch information
jswrenn committed Oct 8, 2024
1 parent 5908912 commit 41b007b
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 1 deletion.
22 changes: 22 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,9 @@ pub unsafe trait KnownLayout {
// resulting size would not fit in a `usize`.
meta.size_for_metadata(Self::LAYOUT)
}

#[doc(hidden)]
unsafe fn drop(slf: &mut UnalignUnsized<Self>);
}

/// The metadata associated with a [`KnownLayout`] type.
Expand Down Expand Up @@ -898,6 +901,25 @@ unsafe impl<T> KnownLayout for [T] {
// struct `Foo(i32, [u8])` or `(u64, Foo)`.
slc.len()
}

#[cfg(feature = "alloc")]
unsafe fn drop(slf: &mut UnalignUnsized<Self>) {
let meta = KnownLayout::pointer_to_metadata(slf);
let size = meta.size_for_metadata(Self::LAYOUT).unwrap();
let aligned = MaybeUninit::<Self>::new_boxed_uninit(meta).unwrap();
let aligned = Box::into_raw(aligned);
// SAFETY: todo
unsafe {
core::ptr::copy_nonoverlapping(slf as *mut _ as *mut u8, aligned as *mut u8, size);
}
let _ = Box::from_raw(aligned);
}

#[cfg(not(feature = "alloc"))]
unsafe fn drop(_: &mut UnalignUnsized<Self>) {
// PME if T needs drop.
static_assert!(T=> !core::mem::needs_drop::<T>());
}
}

#[rustfmt::skip]
Expand Down
13 changes: 12 additions & 1 deletion src/util/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,10 @@ macro_rules! impl_known_layout {
#[inline(always)]
fn pointer_to_metadata(_ptr: *mut Self) -> () {
}

unsafe fn drop(slf: &mut crate::UnalignUnsized<Self>) {
let _ = unsafe { slf.take() };
}
}
};
};
Expand All @@ -563,7 +567,7 @@ macro_rules! impl_known_layout {
/// - It must be valid to perform an `as` cast from `*mut $repr` to `*mut $ty`,
/// and this operation must preserve referent size (ie, `size_of_val_raw`).
macro_rules! unsafe_impl_known_layout {
($($tyvar:ident: ?Sized + KnownLayout =>)? #[repr($repr:ty)] $ty:ty) => {
($($tyvar:ident: ?Sized + KnownLayout =>)? #[repr($(packed,)? $repr:ty)] $ty:ty) => {
const _: () = {
use core::ptr::NonNull;

Expand Down Expand Up @@ -597,6 +601,13 @@ macro_rules! unsafe_impl_known_layout {
let ptr = ptr as *mut $repr;
<$repr>::pointer_to_metadata(ptr)
}

unsafe fn drop(slf: &mut UnalignUnsized<Self>) {
// SAFETY: TODO
let slf = unsafe { &mut *(slf as *mut _ as *mut UnalignUnsized<$repr>) };
// SAFETY: TODO
unsafe { KnownLayout::drop(slf) }
}
}
};
};
Expand Down
83 changes: 83 additions & 0 deletions src/wrappers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,89 @@ impl<T: Unaligned + Display> Display for Unalign<T> {
}
}

/// A type with no alignment requirement.
#[derive(Debug)]
#[repr(C, packed)]
pub struct UnalignUnsized<T: ?Sized>(ManuallyDrop<T>)
where
T: KnownLayout;

// SAFETY: TODO
unsafe impl<T: ?Sized + KnownLayout> KnownLayout for UnalignUnsized<T> {
#[allow(clippy::missing_inline_in_public_items)]
#[cfg_attr(coverage_nightly, coverage(off))]
fn only_derive_is_allowed_to_implement_this_trait() {}

type PointerMetadata = <T as KnownLayout>::PointerMetadata;

type MaybeUninit = UnalignUnsized<<T as KnownLayout>::MaybeUninit>;

const LAYOUT: DstLayout = DstLayout {
// The alignment is `1`, since `Self` is `repr(packed)`.
align: unsafe { NonZeroUsize::new_unchecked(1) },
// Otherwise, we retain the size of the inner `T`.
size_info: <T as KnownLayout>::LAYOUT.size_info,
};

#[inline(always)]
fn raw_from_ptr_len(
bytes: NonNull<u8>,
meta: <T as KnownLayout>::PointerMetadata,
) -> NonNull<Self> {
#[allow(clippy::as_conversions)]
let ptr = <T>::raw_from_ptr_len(bytes, meta).as_ptr() as *mut Self;
unsafe { NonNull::new_unchecked(ptr) }
}

#[inline(always)]
fn pointer_to_metadata(ptr: *mut Self) -> Self::PointerMetadata {
#[allow(clippy::as_conversions)]
let ptr = ptr as *mut T;
<T>::pointer_to_metadata(ptr)
}

#[inline(always)]
unsafe fn drop(slf: &mut UnalignUnsized<Self>) {
let slf = slf.peel();
// SAFETY: TODO
unsafe {
KnownLayout::drop(slf);
}
}
}

impl<T> UnalignUnsized<T>
where
T: KnownLayout,
{
pub(crate) unsafe fn take(&mut self) -> T {
let inner = core::ptr::addr_of!(self.0) as *const _;
// SAFETY: TODO
unsafe { core::ptr::read_unaligned(inner) }
}
}

impl<T: ?Sized> UnalignUnsized<UnalignUnsized<T>>
where
T: KnownLayout,
{
pub(crate) fn peel(&mut self) -> &mut UnalignUnsized<T> {
// SAFETY: TODO
unsafe { &mut *(self as *mut _ as *mut UnalignUnsized<T>) }
}
}

impl<T: ?Sized> Drop for UnalignUnsized<T>
where
T: KnownLayout,
{
fn drop(&mut self) {
if core::mem::needs_drop::<T>() {
unsafe { T::drop(self) }
}
}
}

/// A wrapper type to construct uninitialized instances of `T`.
///
/// `MaybeUninit` is identical to the [standard library
Expand Down

0 comments on commit 41b007b

Please sign in to comment.