Skip to content

Commit

Permalink
Make Unalign::into_inner const (#60)
Browse files Browse the repository at this point in the history
  • Loading branch information
joshlf authored Nov 3, 2022
1 parent 48b3240 commit 7d0bb78
Showing 1 changed file with 32 additions and 4 deletions.
36 changes: 32 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ use core::{
cmp::Ordering,
fmt::{self, Debug, Display, Formatter},
marker::PhantomData,
mem::{self, MaybeUninit},
mem::{self, ManuallyDrop, MaybeUninit},
num::{
NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU128,
NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, Wrapping,
Expand Down Expand Up @@ -863,9 +863,29 @@ impl<T> Unalign<T> {
}

/// Consumes `self`, returning the inner `T`.
pub fn into_inner(self) -> T {
let Unalign(val) = self;
val
pub const fn into_inner(self) -> T {
// Use this instead of `mem::transmute` since the latter can't tell
// that `Unalign<T>` and `T` have the same size.
#[repr(C)]
union Transmute<T> {
u: ManuallyDrop<Unalign<T>>,
t: ManuallyDrop<T>,
}

// SAFETY: Since `Unalign` is `#[repr(C, packed)]`, it has the same
// layout as `T`. `ManuallyDrop<U>` is guaranteed to have the same
// layout as `U`, and so `ManuallyDrop<Unalign<T>>` has the same layout
// as `ManuallyDrop<T>`. Since `Transmute<T>` is `#[repr(C)]`, its `t`
// and `u` fields both start at the same offset (namely, 0) within the
// union.
//
// We do this instead of just destructuring in order to prevent
// `Unalign`'s `Drop::drop` from being run, since dropping is not
// supported in `const fn`s.
//
// TODO(https://github.com/rust-lang/rust/issues/73255): Destructure
// instead of using unsafe.
unsafe { ManuallyDrop::into_inner(Transmute { u: ManuallyDrop::new(self) }.t) }
}

/// Gets an unaligned raw pointer to the inner `T`.
Expand Down Expand Up @@ -2465,6 +2485,14 @@ mod tests {
fn _takes_unaligned(_: &dyn Unaligned) {}
}

#[test]
fn test_unalign_const() {
// Test that some `Unalign` functions and methods are `const`.
const _UNALIGN: Unalign<u64> = Unalign::new(0);
const _UNALIGN_PTR: *const u64 = _UNALIGN.get_ptr();
const _U64: u64 = _UNALIGN.into_inner();
}

#[test]
fn test_read_write() {
const VAL: u64 = 0x12345678;
Expand Down

0 comments on commit 7d0bb78

Please # to comment.