use crate::helpers::dangling_nonnull;
use alloc::alloc::Layout;
use core::{
mem::{align_of, align_of_val, size_of, size_of_val},
ptr::NonNull,
};
#[cfg_attr(
target_pointer_width = "64",
doc = "Exact value: `9_223_372_036_854_775_807`"
)]
#[cfg_attr(target_pointer_width = "32", doc = "Exact value: `2_147_483_647`")]
#[cfg_attr(target_pointer_width = "16", doc = "Exact value: `32_767`")]
pub const USIZE_MAX_NO_HIGH_BIT: usize = usize::MAX >> 1;
#[cfg_attr(
target_pointer_width = "64",
doc = "Exact value: `9_223_372_036_854_775_807`"
)]
#[cfg_attr(target_pointer_width = "32", doc = "Exact value: `2_147_483_647`")]
#[cfg_attr(target_pointer_width = "16", doc = "Exact value: `32_767`")]
pub const USIZE_HIGH_BIT: usize = usize::MAX ^ (usize::MAX >> 1);
#[must_use]
#[inline]
pub const fn usize_bit(bit: u8) -> usize {
USIZE_HIGH_BIT >> bit
}
pub trait SizedProps: Sized {
const SZ: usize = size_of::<Self>();
const ALN: usize = align_of::<Self>();
const LAYOUT: Layout = unsafe { Layout::from_size_align_unchecked(Self::SZ, Self::ALN) };
const IS_ZST: bool = Self::SZ == 0;
const MAX_SLICE_LEN: usize = match Self::SZ {
0 => usize::MAX,
sz => USIZE_MAX_NO_HIGH_BIT / sz,
};
}
impl<T> SizedProps for T {}
pub trait PtrProps<T: ?Sized> {
unsafe fn sz(&self) -> usize;
unsafe fn aln(&self) -> usize;
#[inline]
unsafe fn layout(&self) -> Layout {
Layout::from_size_align_unchecked(self.sz(), self.aln())
}
#[cfg(feature = "metadata")]
unsafe fn metadata(&self) -> <T as core::ptr::Pointee>::Metadata;
unsafe fn is_zst(&self) -> bool {
self.sz() == 0
}
unsafe fn max_slice_len(&self) -> usize {
match self.sz() {
0 => usize::MAX,
sz => USIZE_MAX_NO_HIGH_BIT / sz,
}
}
}
macro_rules! impl_ptr_props_raw {
($($name:ty),* $(,)?) => {
$(
impl<T: ?Sized> PtrProps<T> for $name {
#[inline]
unsafe fn sz(&self) -> usize {
size_of_val::<T>(&**self)
}
#[inline]
unsafe fn aln(&self) -> usize {
align_of_val::<T>(&**self)
}
#[cfg(feature = "metadata")]
unsafe fn metadata(&self) -> <T as core::ptr::Pointee>::Metadata {
core::ptr::metadata(&*(*self))
}
}
)*
};
}
macro_rules! impl_ptr_props_identity {
($($name:ty),* $(,)?) => {
$(
impl<T: ?Sized> PtrProps<T> for $name {
#[inline]
unsafe fn sz(&self) -> usize {
size_of_val::<T>(*self)
}
#[inline]
unsafe fn aln(&self) -> usize {
align_of_val::<T>(*self)
}
#[cfg(feature = "metadata")]
unsafe fn metadata(&self) -> <T as core::ptr::Pointee>::Metadata {
core::ptr::metadata(*self)
}
}
)*
};
}
macro_rules! impl_ptr_props_as_ref {
($($name:ty),* $(,)?) => {
$(
impl<T: ?Sized> PtrProps<T> for $name {
#[inline]
unsafe fn sz(&self) -> usize {
size_of_val::<T>(self.as_ref())
}
#[inline]
unsafe fn aln(&self) -> usize {
align_of_val::<T>(self.as_ref())
}
#[cfg(feature = "metadata")]
unsafe fn metadata(&self) -> <T as core::ptr::Pointee>::Metadata {
core::ptr::metadata(self.as_ref())
}
}
)*
};
}
impl_ptr_props_raw! { *const T, *mut T }
impl_ptr_props_identity! { &T, &mut T }
impl_ptr_props_as_ref! {
alloc::boxed::Box<T>,
alloc::rc::Rc<T>,
alloc::sync::Arc<T>
}
impl<T: ?Sized> PtrProps<T> for NonNull<T> {
#[inline]
unsafe fn sz(&self) -> usize {
size_of_val::<T>(&*self.as_ptr())
}
#[inline]
unsafe fn aln(&self) -> usize {
align_of_val::<T>(&*self.as_ptr())
}
#[cfg(feature = "metadata")]
unsafe fn metadata(&self) -> <T as core::ptr::Pointee>::Metadata {
core::ptr::metadata(&*self.as_ptr())
}
}
#[cfg(not(feature = "metadata"))]
pub unsafe trait VarSized {
type Subtype: Sized + SizedProps;
const ALN: usize = Self::Subtype::ALN;
}
#[cfg(feature = "metadata")]
pub unsafe trait VarSized: crate::marker::SizeMeta {
type Subtype: Sized + SizedProps;
const ALN: usize = Self::Subtype::ALN;
}
unsafe impl<T> VarSized for [T] {
type Subtype = T;
}
unsafe impl VarSized for str {
type Subtype = u8;
}
#[cfg(feature = "c_str")]
unsafe impl VarSized for core::ffi::CStr {
type Subtype = u8;
}
#[cfg(feature = "std")]
unsafe impl VarSized for std::ffi::OsStr {
type Subtype = u8;
}
#[cfg(feature = "std")]
unsafe impl VarSized for std::path::Path {
type Subtype = u8;
}
#[cfg(feature = "const_extras")]
#[must_use]
pub const fn varsized_dangling_nonnull<T: ?Sized + VarSized>() -> NonNull<T> {
varsized_nonnull_from_raw_parts(unsafe { dangling_nonnull(T::ALN) }, 0)
}
#[cfg(not(feature = "const_extras"))]
#[must_use]
pub fn varsized_dangling_nonnull<T: ?Sized + VarSized>() -> NonNull<T> {
varsized_nonnull_from_raw_parts(unsafe { dangling_nonnull(T::ALN) }, 0)
}
#[cfg(feature = "const_extras")]
#[must_use]
pub const fn varsized_dangling_pointer<T: ?Sized + VarSized>() -> *mut T {
varsized_pointer_from_raw_parts(unsafe { dangling_nonnull(T::ALN).as_ptr() }, 0)
}
#[cfg(not(feature = "const_extras"))]
#[must_use]
pub fn varsized_dangling_pointer<T: ?Sized + VarSized>() -> *mut T {
varsized_pointer_from_raw_parts(unsafe { dangling_nonnull(T::ALN).as_ptr() }, 0)
}
#[cfg(feature = "const_extras")]
#[must_use]
#[inline]
pub const fn varsized_nonnull_from_raw_parts<T: ?Sized + VarSized>(
p: NonNull<u8>,
meta: usize,
) -> NonNull<T> {
unsafe { NonNull::new_unchecked(varsized_pointer_from_raw_parts(p.as_ptr(), meta)) }
}
#[cfg(not(feature = "const_extras"))]
#[must_use]
#[inline]
pub fn varsized_nonnull_from_raw_parts<T: ?Sized + VarSized>(
p: NonNull<u8>,
meta: usize,
) -> NonNull<T> {
unsafe { NonNull::new_unchecked(varsized_pointer_from_raw_parts(p.as_ptr(), meta)) }
}
#[cfg(feature = "const_extras")]
#[must_use]
#[inline]
pub const fn varsized_pointer_from_raw_parts<T: ?Sized + VarSized>(
p: *mut u8,
meta: usize,
) -> *mut T {
unsafe {
*((&(p, meta)) as *const (*mut u8, usize)).cast::<*mut T>()
}
}
#[cfg(not(feature = "const_extras"))]
#[must_use]
#[inline]
pub fn varsized_pointer_from_raw_parts<T: ?Sized + VarSized>(p: *mut u8, meta: usize) -> *mut T {
unsafe {
*((&(p, meta)) as *const (*mut u8, usize)).cast::<*mut T>()
}
}