Add is_aligned{,_to}
convenience methods to NonNull
This commit is contained in:
parent
2bcaa9760e
commit
e1b4e8a257
@ -1282,6 +1282,240 @@ impl<T: ?Sized> NonNull<T> {
|
||||
unsafe { ptr::align_offset(self.pointer, align) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether the pointer is properly aligned for `T`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(pointer_is_aligned)]
|
||||
/// use std::ptr::NonNull;
|
||||
///
|
||||
/// // On some platforms, the alignment of i32 is less than 4.
|
||||
/// #[repr(align(4))]
|
||||
/// struct AlignedI32(i32);
|
||||
///
|
||||
/// let data = AlignedI32(42);
|
||||
/// let ptr = NonNull::<AlignedI32>::from(&data);
|
||||
///
|
||||
/// assert!(ptr.is_aligned());
|
||||
/// assert!(!NonNull::new(ptr.as_ptr().wrapping_byte_add(1)).unwrap().is_aligned());
|
||||
/// ```
|
||||
///
|
||||
/// # At compiletime
|
||||
/// **Note: Alignment at compiletime is experimental and subject to change. See the
|
||||
/// [tracking issue] for details.**
|
||||
///
|
||||
/// At compiletime, the compiler may not know where a value will end up in memory.
|
||||
/// Calling this function on a pointer created from a reference at compiletime will only
|
||||
/// return `true` if the pointer is guaranteed to be aligned. This means that the pointer
|
||||
/// is never aligned if cast to a type with a stricter alignment than the reference's
|
||||
/// underlying allocation.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(pointer_is_aligned)]
|
||||
/// #![feature(const_pointer_is_aligned)]
|
||||
/// #![feature(non_null_convenience)]
|
||||
/// #![feature(const_option)]
|
||||
/// #![feature(const_nonnull_new)]
|
||||
/// use std::ptr::NonNull;
|
||||
///
|
||||
/// // On some platforms, the alignment of primitives is less than their size.
|
||||
/// #[repr(align(4))]
|
||||
/// struct AlignedI32(i32);
|
||||
/// #[repr(align(8))]
|
||||
/// struct AlignedI64(i64);
|
||||
///
|
||||
/// const _: () = {
|
||||
/// let data = [AlignedI32(42), AlignedI32(42)];
|
||||
/// let ptr = NonNull::<AlignedI32>::new(&data[0] as *const _ as *mut _).unwrap();
|
||||
/// assert!(ptr.is_aligned());
|
||||
///
|
||||
/// // At runtime either `ptr1` or `ptr2` would be aligned, but at compiletime neither is aligned.
|
||||
/// let ptr1 = ptr.cast::<AlignedI64>();
|
||||
/// let ptr2 = unsafe { ptr.add(1).cast::<AlignedI64>() };
|
||||
/// assert!(!ptr1.is_aligned());
|
||||
/// assert!(!ptr2.is_aligned());
|
||||
/// };
|
||||
/// ```
|
||||
///
|
||||
/// Due to this behavior, it is possible that a runtime pointer derived from a compiletime
|
||||
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(pointer_is_aligned)]
|
||||
/// #![feature(const_pointer_is_aligned)]
|
||||
///
|
||||
/// // On some platforms, the alignment of primitives is less than their size.
|
||||
/// #[repr(align(4))]
|
||||
/// struct AlignedI32(i32);
|
||||
/// #[repr(align(8))]
|
||||
/// struct AlignedI64(i64);
|
||||
///
|
||||
/// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned.
|
||||
/// const COMPTIME_PTR: *const AlignedI32 = &AlignedI32(42);
|
||||
/// const _: () = assert!(!COMPTIME_PTR.cast::<AlignedI64>().is_aligned());
|
||||
/// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).cast::<AlignedI64>().is_aligned());
|
||||
///
|
||||
/// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned.
|
||||
/// let runtime_ptr = COMPTIME_PTR;
|
||||
/// assert_ne!(
|
||||
/// runtime_ptr.cast::<AlignedI64>().is_aligned(),
|
||||
/// runtime_ptr.wrapping_add(1).cast::<AlignedI64>().is_aligned(),
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// If a pointer is created from a fixed address, this function behaves the same during
|
||||
/// runtime and compiletime.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(pointer_is_aligned)]
|
||||
/// #![feature(const_pointer_is_aligned)]
|
||||
/// #![feature(const_option)]
|
||||
/// #![feature(const_nonnull_new)]
|
||||
/// use std::ptr::NonNull;
|
||||
///
|
||||
/// // On some platforms, the alignment of primitives is less than their size.
|
||||
/// #[repr(align(4))]
|
||||
/// struct AlignedI32(i32);
|
||||
/// #[repr(align(8))]
|
||||
/// struct AlignedI64(i64);
|
||||
///
|
||||
/// const _: () = {
|
||||
/// let ptr = NonNull::new(40 as *mut AlignedI32).unwrap();
|
||||
/// assert!(ptr.is_aligned());
|
||||
///
|
||||
/// // For pointers with a known address, runtime and compiletime behavior are identical.
|
||||
/// let ptr1 = ptr.cast::<AlignedI64>();
|
||||
/// let ptr2 = NonNull::new(ptr.as_ptr().wrapping_add(1)).unwrap().cast::<AlignedI64>();
|
||||
/// assert!(ptr1.is_aligned());
|
||||
/// assert!(!ptr2.is_aligned());
|
||||
/// };
|
||||
/// ```
|
||||
///
|
||||
/// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
|
||||
#[unstable(feature = "pointer_is_aligned", issue = "96284")]
|
||||
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub const fn is_aligned(self) -> bool
|
||||
where
|
||||
T: Sized,
|
||||
{
|
||||
self.pointer.is_aligned()
|
||||
}
|
||||
|
||||
/// Returns whether the pointer is aligned to `align`.
|
||||
///
|
||||
/// For non-`Sized` pointees this operation considers only the data pointer,
|
||||
/// ignoring the metadata.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// The function panics if `align` is not a power-of-two (this includes 0).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(pointer_is_aligned)]
|
||||
///
|
||||
/// // On some platforms, the alignment of i32 is less than 4.
|
||||
/// #[repr(align(4))]
|
||||
/// struct AlignedI32(i32);
|
||||
///
|
||||
/// let data = AlignedI32(42);
|
||||
/// let ptr = &data as *const AlignedI32;
|
||||
///
|
||||
/// assert!(ptr.is_aligned_to(1));
|
||||
/// assert!(ptr.is_aligned_to(2));
|
||||
/// assert!(ptr.is_aligned_to(4));
|
||||
///
|
||||
/// assert!(ptr.wrapping_byte_add(2).is_aligned_to(2));
|
||||
/// assert!(!ptr.wrapping_byte_add(2).is_aligned_to(4));
|
||||
///
|
||||
/// assert_ne!(ptr.is_aligned_to(8), ptr.wrapping_add(1).is_aligned_to(8));
|
||||
/// ```
|
||||
///
|
||||
/// # At compiletime
|
||||
/// **Note: Alignment at compiletime is experimental and subject to change. See the
|
||||
/// [tracking issue] for details.**
|
||||
///
|
||||
/// At compiletime, the compiler may not know where a value will end up in memory.
|
||||
/// Calling this function on a pointer created from a reference at compiletime will only
|
||||
/// return `true` if the pointer is guaranteed to be aligned. This means that the pointer
|
||||
/// cannot be stricter aligned than the reference's underlying allocation.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(pointer_is_aligned)]
|
||||
/// #![feature(const_pointer_is_aligned)]
|
||||
///
|
||||
/// // On some platforms, the alignment of i32 is less than 4.
|
||||
/// #[repr(align(4))]
|
||||
/// struct AlignedI32(i32);
|
||||
///
|
||||
/// const _: () = {
|
||||
/// let data = AlignedI32(42);
|
||||
/// let ptr = &data as *const AlignedI32;
|
||||
///
|
||||
/// assert!(ptr.is_aligned_to(1));
|
||||
/// assert!(ptr.is_aligned_to(2));
|
||||
/// assert!(ptr.is_aligned_to(4));
|
||||
///
|
||||
/// // At compiletime, we know for sure that the pointer isn't aligned to 8.
|
||||
/// assert!(!ptr.is_aligned_to(8));
|
||||
/// assert!(!ptr.wrapping_add(1).is_aligned_to(8));
|
||||
/// };
|
||||
/// ```
|
||||
///
|
||||
/// Due to this behavior, it is possible that a runtime pointer derived from a compiletime
|
||||
/// pointer is aligned, even if the compiletime pointer wasn't aligned.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(pointer_is_aligned)]
|
||||
/// #![feature(const_pointer_is_aligned)]
|
||||
///
|
||||
/// // On some platforms, the alignment of i32 is less than 4.
|
||||
/// #[repr(align(4))]
|
||||
/// struct AlignedI32(i32);
|
||||
///
|
||||
/// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned.
|
||||
/// const COMPTIME_PTR: *const AlignedI32 = &AlignedI32(42);
|
||||
/// const _: () = assert!(!COMPTIME_PTR.is_aligned_to(8));
|
||||
/// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).is_aligned_to(8));
|
||||
///
|
||||
/// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned.
|
||||
/// let runtime_ptr = COMPTIME_PTR;
|
||||
/// assert_ne!(
|
||||
/// runtime_ptr.is_aligned_to(8),
|
||||
/// runtime_ptr.wrapping_add(1).is_aligned_to(8),
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// If a pointer is created from a fixed address, this function behaves the same during
|
||||
/// runtime and compiletime.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(pointer_is_aligned)]
|
||||
/// #![feature(const_pointer_is_aligned)]
|
||||
///
|
||||
/// const _: () = {
|
||||
/// let ptr = 40 as *const u8;
|
||||
/// assert!(ptr.is_aligned_to(1));
|
||||
/// assert!(ptr.is_aligned_to(2));
|
||||
/// assert!(ptr.is_aligned_to(4));
|
||||
/// assert!(ptr.is_aligned_to(8));
|
||||
/// assert!(!ptr.is_aligned_to(16));
|
||||
/// };
|
||||
/// ```
|
||||
///
|
||||
/// [tracking issue]: https://github.com/rust-lang/rust/issues/104203
|
||||
#[unstable(feature = "pointer_is_aligned", issue = "96284")]
|
||||
#[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")]
|
||||
#[must_use]
|
||||
#[inline]
|
||||
pub const fn is_aligned_to(self, align: usize) -> bool {
|
||||
self.pointer.is_aligned_to(align)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> NonNull<[T]> {
|
||||
|
Loading…
x
Reference in New Issue
Block a user