#![expect(clippy::inline_always)]
use std::{
cmp,
fmt::{self, Debug},
hash::{Hash, Hasher},
num::NonZeroUsize,
ptr::NonNull,
};
#[repr(transparent)]
#[must_use]
pub struct NonNullConst<T: ?Sized>(NonNull<T>);
impl<T: ?Sized> NonNullConst<T> {
#[inline(always)]
pub const fn new(ptr: *const T) -> Option<Self> {
match NonNull::new(ptr.cast_mut()) {
Some(p) => Some(Self(p)),
None => None,
}
}
#[inline(always)]
pub const unsafe fn new_unchecked(ptr: *const T) -> Self {
Self(unsafe { NonNull::new_unchecked(ptr.cast_mut()) })
}
#[inline(always)]
pub const fn dangling() -> Self
where
T: Sized,
{
Self(NonNull::dangling())
}
#[inline(always)]
pub const fn from_ref(r: &T) -> Self {
Self(NonNull::from_ref(r))
}
#[inline(always)]
pub const fn from_slice_data(slice: &[T]) -> Self
where
T: Sized,
{
NonNullConst::<[T]>::from_ref(slice).as_data_ptr()
}
#[inline(always)]
pub const fn from_non_null(ptr: NonNull<T>) -> Self {
Self(ptr)
}
#[inline(always)]
pub const fn as_ptr(self) -> *const T {
self.0.as_ptr().cast_const()
}
#[inline(always)]
pub const fn as_non_null(self) -> NonNull<T> {
self.0
}
#[inline(always)]
pub const unsafe fn as_ref<'a>(self) -> &'a T {
unsafe { self.0.as_ref() }
}
#[inline(always)]
pub const fn cast<U>(self) -> NonNullConst<U> {
NonNullConst(self.0.cast::<U>())
}
#[inline(always)]
pub const unsafe fn cast_mut(self) -> NonNullMut<T> {
NonNullMut(self.0)
}
#[inline(always)]
pub const unsafe fn add(self, count: usize) -> Self
where
T: Sized,
{
Self(unsafe { self.0.add(count) })
}
#[inline(always)]
pub const unsafe fn sub(self, count: usize) -> Self
where
T: Sized,
{
Self(unsafe { self.0.sub(count) })
}
#[inline(always)]
pub const unsafe fn byte_add(self, count: usize) -> Self {
Self(unsafe { self.0.byte_add(count) })
}
#[inline(always)]
pub const unsafe fn byte_sub(self, count: usize) -> Self {
Self(unsafe { self.0.byte_sub(count) })
}
#[inline(always)]
pub const unsafe fn offset(self, count: isize) -> Self
where
T: Sized,
{
Self(unsafe { self.0.offset(count) })
}
#[inline(always)]
pub unsafe fn offset_from(self, origin: impl IntoNonNull<T>) -> isize
where
T: Sized,
{
unsafe { self.0.offset_from(origin.into_non_null()) }
}
#[inline(always)]
pub unsafe fn offset_from_unsigned(self, origin: impl IntoNonNull<T>) -> usize
where
T: Sized,
{
unsafe { self.0.offset_from_unsigned(origin.into_non_null()) }
}
#[inline(always)]
pub const unsafe fn read(self) -> T
where
T: Sized,
{
unsafe { self.0.read() }
}
#[inline(always)]
pub const unsafe fn read_unaligned(self) -> T
where
T: Sized,
{
unsafe { self.0.read_unaligned() }
}
#[inline(always)]
pub fn addr(self) -> NonZeroUsize {
self.0.addr()
}
#[inline(always)]
pub fn addr_usize(self) -> usize {
self.0.addr().get()
}
#[inline(always)]
pub fn with_addr(self, addr: NonZeroUsize) -> Self {
Self(self.0.with_addr(addr))
}
#[inline(always)]
pub fn map_addr(self, f: impl FnOnce(NonZeroUsize) -> NonZeroUsize) -> Self {
Self(self.0.map_addr(f))
}
#[inline(always)]
pub unsafe fn map_addr_usize(self, f: impl FnOnce(usize) -> usize) -> Self {
Self(self.0.map_addr(|addr| unsafe { NonZeroUsize::new_unchecked(f(addr.get())) }))
}
}
#[repr(transparent)]
#[must_use]
pub struct NonNullMut<T: ?Sized>(NonNull<T>);
impl<T: ?Sized> NonNullMut<T> {
#[inline(always)]
pub const unsafe fn new(ptr: *mut T) -> Option<Self> {
match NonNull::new(ptr) {
Some(p) => Some(Self(p)),
None => None,
}
}
#[inline(always)]
pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
Self(unsafe { NonNull::new_unchecked(ptr) })
}
#[inline(always)]
pub const fn dangling() -> Self
where
T: Sized,
{
Self(NonNull::dangling())
}
#[inline(always)]
pub const fn from_mut(r: &mut T) -> Self {
Self(NonNull::from_mut(r))
}
#[inline(always)]
pub const fn from_slice_data_mut(slice: &mut [T]) -> Self
where
T: Sized,
{
NonNullMut::<[T]>::from_mut(slice).as_data_ptr()
}
#[inline(always)]
pub const unsafe fn from_non_null(ptr: NonNull<T>) -> Self {
Self(ptr)
}
#[inline(always)]
pub const fn as_ptr(self) -> *const T {
self.0.as_ptr().cast_const()
}
#[inline(always)]
pub const fn as_mut_ptr(self) -> *mut T {
self.0.as_ptr()
}
#[inline(always)]
pub const fn as_non_null(self) -> NonNull<T> {
self.0
}
#[inline(always)]
pub const unsafe fn as_ref<'a>(self) -> &'a T {
unsafe { self.0.as_ref() }
}
#[inline(always)]
pub const unsafe fn as_mut<'a>(mut self) -> &'a mut T {
unsafe { self.0.as_mut() }
}
#[inline(always)]
pub const fn cast<U>(self) -> NonNullMut<U> {
NonNullMut(self.0.cast::<U>())
}
#[inline(always)]
pub const fn cast_const(self) -> NonNullConst<T> {
NonNullConst(self.0)
}
#[inline(always)]
pub const unsafe fn add(self, count: usize) -> Self
where
T: Sized,
{
Self(unsafe { self.0.add(count) })
}
#[inline(always)]
pub const unsafe fn sub(self, count: usize) -> Self
where
T: Sized,
{
Self(unsafe { self.0.sub(count) })
}
#[inline(always)]
pub const unsafe fn byte_add(self, count: usize) -> Self {
Self(unsafe { self.0.byte_add(count) })
}
#[inline(always)]
pub const unsafe fn byte_sub(self, count: usize) -> Self {
Self(unsafe { self.0.byte_sub(count) })
}
#[inline(always)]
pub const unsafe fn offset(self, count: isize) -> Self
where
T: Sized,
{
Self(unsafe { self.0.offset(count) })
}
#[inline(always)]
pub unsafe fn offset_from(self, origin: impl IntoNonNull<T>) -> isize
where
T: Sized,
{
unsafe { self.0.offset_from(origin.into_non_null()) }
}
#[inline(always)]
pub unsafe fn offset_from_unsigned(self, origin: impl IntoNonNull<T>) -> usize
where
T: Sized,
{
unsafe { self.0.offset_from_unsigned(origin.into_non_null()) }
}
#[inline(always)]
pub const unsafe fn read(self) -> T
where
T: Sized,
{
unsafe { self.0.read() }
}
#[inline(always)]
pub const unsafe fn read_unaligned(self) -> T
where
T: Sized,
{
unsafe { self.0.read_unaligned() }
}
#[inline(always)]
pub const unsafe fn write(self, val: T)
where
T: Sized,
{
unsafe { self.0.write(val) }
}
#[inline(always)]
pub const unsafe fn write_unaligned(self, val: T)
where
T: Sized,
{
unsafe { self.0.write_unaligned(val) }
}
#[inline(always)]
pub const unsafe fn write_bytes(self, val: u8, count: usize)
where
T: Sized,
{
unsafe { self.0.write_bytes(val, count) }
}
#[inline(always)]
pub const unsafe fn replace(self, val: T) -> T
where
T: Sized,
{
unsafe { self.0.replace(val) }
}
#[inline(always)]
pub unsafe fn copy_from(self, src: impl IntoNonNull<T>, count: usize)
where
T: Sized,
{
unsafe { self.0.copy_from(src.into_non_null(), count) }
}
#[inline(always)]
pub unsafe fn copy_nonoverlapping_from(self, src: impl IntoNonNull<T>, count: usize)
where
T: Sized,
{
unsafe { self.0.copy_from_nonoverlapping(src.into_non_null(), count) }
}
#[inline(always)]
pub unsafe fn drop_in_place(self) {
unsafe { self.0.drop_in_place() }
}
#[inline(always)]
pub fn addr(self) -> NonZeroUsize {
self.0.addr()
}
#[inline(always)]
pub fn addr_usize(self) -> usize {
self.0.addr().get()
}
#[inline(always)]
pub fn with_addr(self, addr: NonZeroUsize) -> Self {
Self(self.0.with_addr(addr))
}
#[inline(always)]
pub fn map_addr(self, f: impl FnOnce(NonZeroUsize) -> NonZeroUsize) -> Self {
Self(self.0.map_addr(f))
}
#[inline(always)]
pub unsafe fn map_addr_usize(self, f: impl FnOnce(usize) -> usize) -> Self {
Self(self.0.map_addr(|addr| unsafe { NonZeroUsize::new_unchecked(f(addr.get())) }))
}
}
impl<T, const N: usize> NonNullConst<[T; N]> {
#[expect(clippy::unused_self)]
#[inline(always)]
pub const fn len(self) -> usize {
N
}
#[expect(clippy::unused_self)]
#[inline(always)]
pub const fn is_empty(self) -> bool {
N == 0
}
#[inline(always)]
pub const fn as_data_ptr(self) -> NonNullConst<T> {
NonNullConst(self.0.cast::<T>())
}
}
impl<T, const N: usize> NonNullMut<[T; N]> {
#[expect(clippy::unused_self)]
#[inline(always)]
pub const fn len(self) -> usize {
N
}
#[expect(clippy::unused_self)]
#[inline(always)]
pub const fn is_empty(self) -> bool {
N == 0
}
#[inline(always)]
pub const fn as_data_ptr(self) -> NonNullMut<T> {
NonNullMut(self.0.cast::<T>())
}
}
impl<T> NonNullConst<[T]> {
#[inline(always)]
pub const fn slice_from_raw_parts(data: NonNullConst<T>, len: usize) -> Self {
Self(NonNull::slice_from_raw_parts(data.0, len))
}
#[inline(always)]
pub const fn len(self) -> usize {
self.0.len()
}
#[inline(always)]
pub const fn is_empty(self) -> bool {
self.0.is_empty()
}
#[inline(always)]
pub const fn as_data_ptr(self) -> NonNullConst<T> {
NonNullConst(self.0.cast::<T>())
}
}
impl<T> NonNullMut<[T]> {
#[inline(always)]
pub const fn slice_from_raw_parts(data: NonNullMut<T>, len: usize) -> Self {
Self(NonNull::slice_from_raw_parts(data.0, len))
}
#[inline(always)]
pub const fn len(self) -> usize {
self.0.len()
}
#[inline(always)]
pub const fn is_empty(self) -> bool {
self.0.is_empty()
}
#[inline(always)]
pub const fn as_data_ptr(self) -> NonNullMut<T> {
NonNullMut(self.0.cast::<T>())
}
}
#[expect(private_bounds)]
pub trait IntoNonNull<T: ?Sized>: Sealed {
fn into_non_null(self) -> NonNull<T>;
}
trait Sealed {}
impl<T: ?Sized> IntoNonNull<T> for NonNull<T> {
#[inline(always)]
fn into_non_null(self) -> NonNull<T> {
self
}
}
impl<T: ?Sized> Sealed for NonNull<T> {}
impl<T: ?Sized> IntoNonNull<T> for NonNullConst<T> {
#[inline(always)]
fn into_non_null(self) -> NonNull<T> {
self.0
}
}
impl<T: ?Sized> Sealed for NonNullConst<T> {}
impl<T: ?Sized> IntoNonNull<T> for NonNullMut<T> {
#[inline(always)]
fn into_non_null(self) -> NonNull<T> {
self.0
}
}
impl<T: ?Sized> Sealed for NonNullMut<T> {}
impl<T: ?Sized> Copy for NonNullConst<T> {}
impl<T: ?Sized> Clone for NonNullConst<T> {
#[inline(always)]
fn clone(&self) -> Self {
*self
}
}
impl<T: ?Sized> Copy for NonNullMut<T> {}
impl<T: ?Sized> Clone for NonNullMut<T> {
#[inline(always)]
fn clone(&self) -> Self {
*self
}
}
impl<T: ?Sized> From<&T> for NonNullConst<T> {
#[inline(always)]
fn from(r: &T) -> Self {
Self::from_ref(r)
}
}
impl<T: ?Sized> From<&mut T> for NonNullConst<T> {
#[inline(always)]
fn from(r: &mut T) -> Self {
Self(NonNull::from_ref(r))
}
}
impl<T: ?Sized> From<&mut T> for NonNullMut<T> {
#[inline(always)]
fn from(r: &mut T) -> Self {
Self(NonNull::from_mut(r))
}
}
impl<T: ?Sized> From<NonNull<T>> for NonNullConst<T> {
#[inline(always)]
fn from(ptr: NonNull<T>) -> Self {
Self::from_non_null(ptr)
}
}
impl<T: ?Sized> From<NonNullMut<T>> for NonNullConst<T> {
#[inline(always)]
fn from(ptr: NonNullMut<T>) -> Self {
ptr.cast_const()
}
}
#[expect(ambiguous_wide_pointer_comparisons)]
impl<T: ?Sized> PartialEq for NonNullConst<T> {
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
self.0.eq(&other.0)
}
}
impl<T: ?Sized> Eq for NonNullConst<T> {}
#[expect(ambiguous_wide_pointer_comparisons)]
impl<T: ?Sized> PartialEq for NonNullMut<T> {
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
self.0.eq(&other.0)
}
}
impl<T: ?Sized> Eq for NonNullMut<T> {}
#[expect(clippy::non_canonical_partial_ord_impl, ambiguous_wide_pointer_comparisons)]
impl<T: ?Sized> PartialOrd for NonNullConst<T> {
#[inline(always)]
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
self.0.partial_cmp(&other.0)
}
}
#[expect(ambiguous_wide_pointer_comparisons)]
impl<T: ?Sized> Ord for NonNullConst<T> {
#[inline(always)]
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.0.cmp(&other.0)
}
}
#[expect(clippy::non_canonical_partial_ord_impl, ambiguous_wide_pointer_comparisons)]
impl<T: ?Sized> PartialOrd for NonNullMut<T> {
#[inline(always)]
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
self.0.partial_cmp(&other.0)
}
}
#[expect(ambiguous_wide_pointer_comparisons)]
impl<T: ?Sized> Ord for NonNullMut<T> {
#[inline(always)]
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.0.cmp(&other.0)
}
}
impl<T: ?Sized> Hash for NonNullConst<T> {
#[inline(always)]
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
impl<T: ?Sized> Hash for NonNullMut<T> {
#[inline(always)]
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
impl<T: ?Sized> Debug for NonNullConst<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Debug::fmt(&self.0, f)
}
}
impl<T: ?Sized> Debug for NonNullMut<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Debug::fmt(&self.0, f)
}
}
impl<T: ?Sized> fmt::Pointer for NonNullConst<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Pointer::fmt(&self.0, f)
}
}
impl<T: ?Sized> fmt::Pointer for NonNullMut<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Pointer::fmt(&self.0, f)
}
}
#[cfg(test)]
mod tests {
use super::{NonNullConst, NonNullMut};
#[test]
fn new_returns_none_for_null() {
use std::ptr;
assert!(NonNullConst::<u32>::new(ptr::null()).is_none());
assert!(unsafe { NonNullMut::<u32>::new(ptr::null_mut()) }.is_none());
}
#[test]
fn new_returns_some_for_non_null() {
let n = 0u32;
let p = &raw const n;
assert!(NonNullConst::new(p).is_some());
let mut n = 0u32;
let p = &raw mut n;
assert!(unsafe { NonNullMut::new(p) }.is_some());
}
#[test]
fn cast_const_and_cast_mut_round_trip() {
let mut n = 0u32;
let mut_ptr = NonNullMut::from_mut(&mut n);
let const_ptr = mut_ptr.cast_const();
assert_eq!(mut_ptr.as_ptr(), const_ptr.as_ptr());
let round_tripped_mut_ptr = unsafe { const_ptr.cast_mut() };
assert_eq!(round_tripped_mut_ptr, mut_ptr);
}
#[test]
fn addr_usize_matches_addr() {
let n = 0u32;
let ptr = NonNullConst::from_ref(&n);
assert_eq!(ptr.addr_usize(), ptr.addr().get());
}
#[test]
fn map_addr_usize() {
let arr = [0u8; 4];
let first = NonNullConst::from_ref(&arr[0]);
let second = NonNullConst::from_ref(&arr[1]);
let mapped = unsafe { first.map_addr_usize(|a| a + 1) };
assert_eq!(mapped.as_ptr(), second.as_ptr());
let mut arr = [0u8; 4];
let first = NonNullMut::from_slice_data_mut(&mut arr);
let mapped = unsafe { first.map_addr_usize(|a| a + 1) };
assert_eq!(mapped.addr_usize(), first.addr_usize() + 1);
}
#[test]
fn from_slice_data_points_to_first_element() {
let arr: [u32; 3] = [1, 2, 3];
let ptr = NonNullConst::from_slice_data(&arr);
assert_eq!(ptr.as_ptr(), arr.as_ptr());
assert_eq!(unsafe { ptr.read() }, 1);
}
#[test]
fn from_slice_data_mut_points_to_first_element() {
let mut arr: [u32; 3] = [1, 2, 3];
let expected = arr.as_mut_ptr();
let ptr = NonNullMut::from_slice_data_mut(&mut arr);
assert_eq!(ptr.as_mut_ptr(), expected);
assert_eq!(unsafe { ptr.read() }, 1);
}
#[test]
fn as_data_ptr_on_slice_points_to_first_element() {
let arr: [u32; 3] = [1, 2, 3];
let slice_ptr = NonNullConst::from_ref(&arr[..]);
let data_ptr = slice_ptr.as_data_ptr();
assert_eq!(data_ptr.as_ptr(), arr.as_ptr());
let mut arr: [u32; 3] = [1, 2, 3];
let slice_ptr = NonNullMut::from_mut(&mut arr[..]);
let data_ptr = slice_ptr.as_data_ptr();
assert_eq!(data_ptr.as_mut_ptr(), arr.as_mut_ptr());
}
#[test]
fn as_data_ptr_on_array_points_to_first_element() {
let arr: [u32; 3] = [1, 2, 3];
let arr_ptr = NonNullConst::from_ref(&arr);
let data_ptr = arr_ptr.as_data_ptr();
assert_eq!(data_ptr.as_ptr(), arr.as_ptr());
let mut arr: [u32; 3] = [1, 2, 3];
let arr_ptr = NonNullMut::from_mut(&mut arr);
let data_ptr = arr_ptr.as_data_ptr();
assert_eq!(data_ptr.as_mut_ptr(), arr.as_mut_ptr());
}
#[test]
fn slice_len_and_is_empty() {
let arr: [u32; 3] = [1, 2, 3];
let ptr = NonNullConst::from_ref(&arr[..]);
assert_eq!(ptr.len(), 3);
assert!(!ptr.is_empty());
let empty: [u32; 0] = [];
let empty_ptr = NonNullConst::from_ref(&empty[..]);
assert_eq!(empty_ptr.len(), 0);
assert!(empty_ptr.is_empty());
let mut arr: [u32; 3] = [1, 2, 3];
let ptr = NonNullMut::from_mut(&mut arr[..]);
assert_eq!(ptr.len(), 3);
assert!(!ptr.is_empty());
let mut empty: [u32; 0] = [];
let empty_ptr = NonNullMut::from_mut(&mut empty[..]);
assert_eq!(empty_ptr.len(), 0);
assert!(empty_ptr.is_empty());
}
#[test]
fn array_len_and_is_empty() {
let arr: [u32; 3] = [1, 2, 3];
let ptr = NonNullConst::from_ref(&arr);
assert_eq!(ptr.len(), 3);
assert!(!ptr.is_empty());
let empty: [u32; 0] = [];
let empty_ptr = NonNullConst::from_ref(&empty);
assert_eq!(empty_ptr.len(), 0);
assert!(empty_ptr.is_empty());
let mut arr: [u32; 3] = [1, 2, 3];
let ptr = NonNullMut::from_mut(&mut arr);
assert_eq!(ptr.len(), 3);
assert!(!ptr.is_empty());
let mut empty: [u32; 0] = [];
let empty_ptr = NonNullMut::from_mut(&mut empty);
assert_eq!(empty_ptr.len(), 0);
assert!(empty_ptr.is_empty());
}
#[test]
fn offset_from_accepts_all_pointer_types() {
let mut arr = [0u32; 4];
let base_const = NonNullConst::from_ref(&arr[0]);
let base_mut = NonNullMut::from_mut(&mut arr[0]);
let base_non_null = base_const.as_non_null();
let tip_const = NonNullConst::from_ref(&arr[3]);
let tip_mut = NonNullMut::from_mut(&mut arr[3]);
unsafe {
assert_eq!(tip_const.offset_from(base_const), 3);
assert_eq!(tip_const.offset_from(base_mut), 3);
assert_eq!(tip_const.offset_from(base_non_null), 3);
assert_eq!(tip_mut.offset_from(base_const), 3);
assert_eq!(tip_mut.offset_from(base_mut), 3);
assert_eq!(tip_mut.offset_from(base_non_null), 3);
}
}
#[test]
fn offset_from_unsigned_accepts_all_pointer_types() {
let mut arr = [0u32; 4];
let base_const = NonNullConst::from_ref(&arr[0]);
let base_mut = NonNullMut::from_mut(&mut arr[0]);
let base_non_null = base_const.as_non_null();
let tip_const = NonNullConst::from_ref(&arr[3]);
let tip_mut = NonNullMut::from_mut(&mut arr[3]);
unsafe {
assert_eq!(tip_const.offset_from_unsigned(base_const), 3);
assert_eq!(tip_const.offset_from_unsigned(base_mut), 3);
assert_eq!(tip_const.offset_from_unsigned(base_non_null), 3);
assert_eq!(tip_mut.offset_from_unsigned(base_const), 3);
assert_eq!(tip_mut.offset_from_unsigned(base_mut), 3);
assert_eq!(tip_mut.offset_from_unsigned(base_non_null), 3);
}
}
#[test]
fn copy_nonoverlapping_from_accepts_all_pointer_types() {
let src: [u32; 3] = [1, 2, 3];
let src_ptr = NonNullConst::from_slice_data(&src);
let mut dst = [0u32; 3];
let dst_ptr = NonNullMut::from_slice_data_mut(&mut dst);
unsafe { dst_ptr.copy_nonoverlapping_from(src_ptr, 3) };
assert_eq!(dst, [1, 2, 3]);
let mut src: [u32; 3] = [1, 2, 3];
let src_ptr = NonNullMut::from_slice_data_mut(&mut src);
let mut dst = [0u32; 3];
let dst_ptr = NonNullMut::from_slice_data_mut(&mut dst);
unsafe { dst_ptr.copy_nonoverlapping_from(src_ptr, 3) };
assert_eq!(dst, [1, 2, 3]);
let src: [u32; 3] = [1, 2, 3];
let src_ptr = NonNullConst::from_slice_data(&src).as_non_null();
let mut dst = [0u32; 3];
let dst_ptr = NonNullMut::from_slice_data_mut(&mut dst);
unsafe { dst_ptr.copy_nonoverlapping_from(src_ptr, 3) };
assert_eq!(dst, [1, 2, 3]);
}
#[test]
fn copy_from_allows_overlapping() {
let mut arr: [u32; 7] = [1, 2, 3, 4, 5, 6, 7];
let base = NonNullMut::from_slice_data_mut(&mut arr);
let src = base.cast_const();
let dst = unsafe { base.add(2) };
unsafe { dst.copy_from(src, 3) };
assert_eq!(arr, [1, 2, 1, 2, 3, 6, 7]);
let mut arr: [u32; 7] = [1, 2, 3, 4, 5, 6, 7];
let base = NonNullMut::from_slice_data_mut(&mut arr);
let src = base;
let dst = unsafe { base.add(2) };
unsafe { dst.copy_from(src, 3) };
assert_eq!(arr, [1, 2, 1, 2, 3, 6, 7]);
let mut arr: [u32; 7] = [1, 2, 3, 4, 5, 6, 7];
let base = NonNullMut::from_slice_data_mut(&mut arr);
let src = base.as_non_null();
let dst = unsafe { base.add(2) };
unsafe { dst.copy_from(src, 3) };
assert_eq!(arr, [1, 2, 1, 2, 3, 6, 7]);
}
#[test]
fn eq() {
let arr = [0u32; 2];
let a = NonNullConst::from_ref(&arr[0]);
let b = NonNullConst::from_ref(&arr[0]);
let c = NonNullConst::from_ref(&arr[1]);
assert_eq!(a, b);
assert_ne!(a, c);
let mut arr = [0u32; 2];
let a = NonNullMut::from_slice_data_mut(&mut arr);
let b = a;
let c = unsafe { a.add(1) };
assert_eq!(a, b);
assert_ne!(a, c);
}
#[test]
fn ord() {
use std::cmp::Ordering;
let arr = [0u32; 3];
let a = NonNullConst::from_ref(&arr[0]);
let b = NonNullConst::from_ref(&arr[1]);
let c = NonNullConst::from_ref(&arr[2]);
assert!(a < b);
assert!(b > a);
assert!(a < c);
assert!(c > a);
assert!(b < c);
assert!(c > b);
assert!(a <= a);
assert!(a >= a);
assert_eq!(a.cmp(&a), Ordering::Equal);
assert_eq!(a.partial_cmp(&a), Some(Ordering::Equal));
let mut arr = [0u32; 3];
let base = NonNullMut::from_slice_data_mut(&mut arr);
let a = base;
let (b, c) = unsafe { (base.add(1), base.add(2)) };
assert!(a < b);
assert!(b > a);
assert!(a < c);
assert!(c > a);
assert!(b < c);
assert!(c > b);
assert!(a <= a);
assert!(a >= a);
assert_eq!(a.cmp(&a), Ordering::Equal);
assert_eq!(a.partial_cmp(&a), Some(Ordering::Equal));
}
#[test]
fn hash() {
use std::hash::{DefaultHasher, Hash, Hasher};
fn hash_of<T: Hash>(val: &T) -> u64 {
let mut hasher = DefaultHasher::new();
val.hash(&mut hasher);
hasher.finish()
}
let arr = [0u32; 2];
let a = NonNullConst::from_ref(&arr[0]);
let b = NonNullConst::from_ref(&arr[0]);
let c = NonNullConst::from_ref(&arr[1]);
assert_eq!(hash_of(&a), hash_of(&b));
assert_ne!(hash_of(&a), hash_of(&c));
let mut arr = [0u32; 2];
let a = NonNullMut::from_slice_data_mut(&mut arr);
let (b, c) = unsafe { (a.add(0), a.add(1)) };
assert_eq!(hash_of(&a), hash_of(&b));
assert_ne!(hash_of(&a), hash_of(&c));
let mut x = 0u32;
let const_ptr = NonNullConst::from_ref(&x);
let mut_ptr = NonNullMut::from_mut(&mut x);
assert_eq!(hash_of(&const_ptr), hash_of(&mut_ptr));
}
#[test]
fn not_send_or_sync() {
use crate::types::implements;
assert!(implements!(NonNullConst<u32>: !Send));
assert!(implements!(NonNullConst<u32>: !Sync));
assert!(implements!(NonNullMut<u32>: !Send));
assert!(implements!(NonNullMut<u32>: !Sync));
}
}