#![cfg(feature = "extern_crate_alloc")]
#![allow(clippy::duplicated_attributes)]
use super::*;
#[cfg(target_has_atomic = "ptr")]
use alloc::sync::Arc;
use alloc::{
alloc::{alloc_zeroed, Layout},
boxed::Box,
rc::Rc,
vec,
vec::Vec,
};
use core::{
mem::{size_of_val, ManuallyDrop},
ops::{Deref, DerefMut},
};
#[inline]
pub fn cast_box<A: NoUninit, B: AnyBitPattern>(input: Box<A>) -> Box<B> {
try_cast_box(input).map_err(|(e, _v)| e).unwrap()
}
#[inline]
pub fn try_cast_box<A: NoUninit, B: AnyBitPattern>(
input: Box<A>,
) -> Result<Box<B>, (PodCastError, Box<A>)> {
if align_of::<A>() != align_of::<B>() {
Err((PodCastError::AlignmentMismatch, input))
} else if size_of::<A>() != size_of::<B>() {
Err((PodCastError::SizeMismatch, input))
} else {
let ptr: *mut B = Box::into_raw(input) as *mut B;
Ok(unsafe { Box::from_raw(ptr) })
}
}
#[inline]
pub fn try_zeroed_box<T: Zeroable>() -> Result<Box<T>, ()> {
if size_of::<T>() == 0 {
let ptr = core::ptr::NonNull::dangling().as_ptr();
return Ok(unsafe { Box::from_raw(ptr) });
}
let layout = Layout::new::<T>();
let ptr = unsafe { alloc_zeroed(layout) };
if ptr.is_null() {
Err(())
} else {
Ok(unsafe { Box::<T>::from_raw(ptr as *mut T) })
}
}
#[inline]
pub fn zeroed_box<T: Zeroable>() -> Box<T> {
try_zeroed_box().unwrap()
}
pub fn try_zeroed_vec<T: Zeroable>(length: usize) -> Result<Vec<T>, ()> {
if length == 0 {
Ok(Vec::new())
} else {
let boxed_slice = try_zeroed_slice_box(length)?;
Ok(boxed_slice.into_vec())
}
}
pub fn zeroed_vec<T: Zeroable>(length: usize) -> Vec<T> {
try_zeroed_vec(length).unwrap()
}
#[inline]
pub fn try_zeroed_slice_box<T: Zeroable>(
length: usize,
) -> Result<Box<[T]>, ()> {
if size_of::<T>() == 0 || length == 0 {
let ptr = core::ptr::NonNull::dangling().as_ptr();
let slice_ptr = core::ptr::slice_from_raw_parts_mut(ptr, length);
return Ok(unsafe { Box::from_raw(slice_ptr) });
}
let layout = core::alloc::Layout::array::<T>(length).map_err(|_| ())?;
let ptr = unsafe { alloc_zeroed(layout) };
if ptr.is_null() {
Err(())
} else {
let slice =
unsafe { core::slice::from_raw_parts_mut(ptr as *mut T, length) };
Ok(unsafe { Box::<[T]>::from_raw(slice) })
}
}
pub fn zeroed_slice_box<T: Zeroable>(length: usize) -> Box<[T]> {
try_zeroed_slice_box(length).unwrap()
}
#[cfg(all(feature = "alloc_uninit", target_has_atomic = "ptr"))]
pub fn zeroed_arc<T: Zeroable>() -> Arc<T> {
let mut arc = Arc::new_uninit();
crate::write_zeroes(Arc::get_mut(&mut arc).unwrap()); unsafe { arc.assume_init() }
}
#[cfg(all(feature = "alloc_uninit", target_has_atomic = "ptr"))]
pub fn zeroed_arc_slice<T: Zeroable>(length: usize) -> Arc<[T]> {
let mut arc = Arc::new_uninit_slice(length);
crate::fill_zeroes(Arc::get_mut(&mut arc).unwrap()); unsafe { arc.assume_init() }
}
#[cfg(feature = "alloc_uninit")]
pub fn zeroed_rc<T: Zeroable>() -> Rc<T> {
let mut rc = Rc::new_uninit();
crate::write_zeroes(Rc::get_mut(&mut rc).unwrap()); unsafe { rc.assume_init() }
}
#[cfg(feature = "alloc_uninit")]
pub fn zeroed_rc_slice<T: Zeroable>(length: usize) -> Rc<[T]> {
let mut rc = Rc::new_uninit_slice(length);
crate::fill_zeroes(Rc::get_mut(&mut rc).unwrap()); unsafe { rc.assume_init() }
}
#[inline]
pub fn cast_slice_box<A: NoUninit, B: AnyBitPattern>(
input: Box<[A]>,
) -> Box<[B]> {
try_cast_slice_box(input).map_err(|(e, _v)| e).unwrap()
}
#[inline]
pub fn try_cast_slice_box<A: NoUninit, B: AnyBitPattern>(
input: Box<[A]>,
) -> Result<Box<[B]>, (PodCastError, Box<[A]>)> {
if align_of::<A>() != align_of::<B>() {
Err((PodCastError::AlignmentMismatch, input))
} else if size_of::<A>() != size_of::<B>() {
let input_bytes = size_of_val::<[A]>(&*input);
if (size_of::<B>() == 0 && input_bytes != 0)
|| (size_of::<B>() != 0 && input_bytes % size_of::<B>() != 0)
{
Err((PodCastError::OutputSliceWouldHaveSlop, input))
} else {
let length =
if size_of::<B>() != 0 { input_bytes / size_of::<B>() } else { 0 };
let box_ptr: *mut A = Box::into_raw(input) as *mut A;
let ptr: *mut [B] =
unsafe { core::slice::from_raw_parts_mut(box_ptr as *mut B, length) };
Ok(unsafe { Box::<[B]>::from_raw(ptr) })
}
} else {
let box_ptr: *mut [A] = Box::into_raw(input);
let ptr: *mut [B] = box_ptr as *mut [B];
Ok(unsafe { Box::<[B]>::from_raw(ptr) })
}
}
#[inline]
pub fn cast_vec<A: NoUninit, B: AnyBitPattern>(input: Vec<A>) -> Vec<B> {
try_cast_vec(input).map_err(|(e, _v)| e).unwrap()
}
#[inline]
pub fn try_cast_vec<A: NoUninit, B: AnyBitPattern>(
input: Vec<A>,
) -> Result<Vec<B>, (PodCastError, Vec<A>)> {
if align_of::<A>() != align_of::<B>() {
Err((PodCastError::AlignmentMismatch, input))
} else if size_of::<A>() != size_of::<B>() {
let input_size = size_of_val::<[A]>(&*input);
let input_capacity = input.capacity() * size_of::<A>();
if (size_of::<B>() == 0 && input_capacity != 0)
|| (size_of::<B>() != 0
&& (input_size % size_of::<B>() != 0
|| input_capacity % size_of::<B>() != 0))
{
Err((PodCastError::OutputSliceWouldHaveSlop, input))
} else {
let length: usize =
if size_of::<B>() != 0 { input_size / size_of::<B>() } else { 0 };
let capacity: usize =
if size_of::<B>() != 0 { input_capacity / size_of::<B>() } else { 0 };
let mut manual_drop_vec = ManuallyDrop::new(input);
let vec_ptr: *mut A = manual_drop_vec.as_mut_ptr();
let ptr: *mut B = vec_ptr as *mut B;
Ok(unsafe { Vec::from_raw_parts(ptr, length, capacity) })
}
} else {
let length: usize = input.len();
let capacity: usize = input.capacity();
let mut manual_drop_vec = ManuallyDrop::new(input);
let vec_ptr: *mut A = manual_drop_vec.as_mut_ptr();
let ptr: *mut B = vec_ptr as *mut B;
Ok(unsafe { Vec::from_raw_parts(ptr, length, capacity) })
}
}
pub fn pod_collect_to_vec<A: NoUninit, B: NoUninit + AnyBitPattern>(
src: &[A],
) -> Vec<B> {
let src_size = core::mem::size_of_val(src);
let dst_count = src_size / size_of::<B>()
+ if src_size % size_of::<B>() != 0 { 1 } else { 0 };
let mut dst = vec![B::zeroed(); dst_count];
let src_bytes: &[u8] = cast_slice(src);
let dst_bytes: &mut [u8] = cast_slice_mut(&mut dst[..]);
dst_bytes[..src_size].copy_from_slice(src_bytes);
dst
}
#[inline]
pub fn cast_rc<A: NoUninit + AnyBitPattern, B: NoUninit + AnyBitPattern>(
input: Rc<A>,
) -> Rc<B> {
try_cast_rc(input).map_err(|(e, _v)| e).unwrap()
}
#[inline]
pub fn try_cast_rc<A: NoUninit + AnyBitPattern, B: NoUninit + AnyBitPattern>(
input: Rc<A>,
) -> Result<Rc<B>, (PodCastError, Rc<A>)> {
if align_of::<A>() != align_of::<B>() {
Err((PodCastError::AlignmentMismatch, input))
} else if size_of::<A>() != size_of::<B>() {
Err((PodCastError::SizeMismatch, input))
} else {
let ptr: *const B = Rc::into_raw(input) as *const B;
Ok(unsafe { Rc::from_raw(ptr) })
}
}
#[inline]
#[cfg(target_has_atomic = "ptr")]
pub fn cast_arc<A: NoUninit + AnyBitPattern, B: NoUninit + AnyBitPattern>(
input: Arc<A>,
) -> Arc<B> {
try_cast_arc(input).map_err(|(e, _v)| e).unwrap()
}
#[inline]
#[cfg(target_has_atomic = "ptr")]
pub fn try_cast_arc<
A: NoUninit + AnyBitPattern,
B: NoUninit + AnyBitPattern,
>(
input: Arc<A>,
) -> Result<Arc<B>, (PodCastError, Arc<A>)> {
if align_of::<A>() != align_of::<B>() {
Err((PodCastError::AlignmentMismatch, input))
} else if size_of::<A>() != size_of::<B>() {
Err((PodCastError::SizeMismatch, input))
} else {
let ptr: *const B = Arc::into_raw(input) as *const B;
Ok(unsafe { Arc::from_raw(ptr) })
}
}
#[inline]
pub fn cast_slice_rc<
A: NoUninit + AnyBitPattern,
B: NoUninit + AnyBitPattern,
>(
input: Rc<[A]>,
) -> Rc<[B]> {
try_cast_slice_rc(input).map_err(|(e, _v)| e).unwrap()
}
#[inline]
pub fn try_cast_slice_rc<
A: NoUninit + AnyBitPattern,
B: NoUninit + AnyBitPattern,
>(
input: Rc<[A]>,
) -> Result<Rc<[B]>, (PodCastError, Rc<[A]>)> {
if align_of::<A>() != align_of::<B>() {
Err((PodCastError::AlignmentMismatch, input))
} else if size_of::<A>() != size_of::<B>() {
let input_bytes = size_of_val::<[A]>(&*input);
if (size_of::<B>() == 0 && input_bytes != 0)
|| (size_of::<B>() != 0 && input_bytes % size_of::<B>() != 0)
{
Err((PodCastError::OutputSliceWouldHaveSlop, input))
} else {
let length =
if size_of::<B>() != 0 { input_bytes / size_of::<B>() } else { 0 };
let rc_ptr: *const A = Rc::into_raw(input) as *const A;
let ptr = core::ptr::slice_from_raw_parts(rc_ptr as *const B, length);
Ok(unsafe { Rc::<[B]>::from_raw(ptr) })
}
} else {
let rc_ptr: *const [A] = Rc::into_raw(input);
let ptr: *const [B] = rc_ptr as *const [B];
Ok(unsafe { Rc::<[B]>::from_raw(ptr) })
}
}
#[inline]
#[cfg(target_has_atomic = "ptr")]
pub fn cast_slice_arc<
A: NoUninit + AnyBitPattern,
B: NoUninit + AnyBitPattern,
>(
input: Arc<[A]>,
) -> Arc<[B]> {
try_cast_slice_arc(input).map_err(|(e, _v)| e).unwrap()
}
#[inline]
#[cfg(target_has_atomic = "ptr")]
pub fn try_cast_slice_arc<
A: NoUninit + AnyBitPattern,
B: NoUninit + AnyBitPattern,
>(
input: Arc<[A]>,
) -> Result<Arc<[B]>, (PodCastError, Arc<[A]>)> {
if align_of::<A>() != align_of::<B>() {
Err((PodCastError::AlignmentMismatch, input))
} else if size_of::<A>() != size_of::<B>() {
let input_bytes = size_of_val::<[A]>(&*input);
if (size_of::<B>() == 0 && input_bytes != 0)
|| (size_of::<B>() != 0 && input_bytes % size_of::<B>() != 0)
{
Err((PodCastError::OutputSliceWouldHaveSlop, input))
} else {
let length =
if size_of::<B>() != 0 { input_bytes / size_of::<B>() } else { 0 };
let arc_ptr: *const A = Arc::into_raw(input) as *const A;
let ptr = core::ptr::slice_from_raw_parts(arc_ptr as *const B, length);
Ok(unsafe { Arc::<[B]>::from_raw(ptr) })
}
} else {
let arc_ptr: *const [A] = Arc::into_raw(input);
let ptr: *const [B] = arc_ptr as *const [B];
Ok(unsafe { Arc::<[B]>::from_raw(ptr) })
}
}
pub trait TransparentWrapperAlloc<Inner: ?Sized>:
TransparentWrapper<Inner>
{
fn wrap_vec(s: Vec<Inner>) -> Vec<Self>
where
Self: Sized,
Inner: Sized,
{
let mut s = ManuallyDrop::new(s);
let length = s.len();
let capacity = s.capacity();
let ptr = s.as_mut_ptr();
unsafe {
Vec::from_raw_parts(ptr as *mut Self, length, capacity)
}
}
#[inline]
fn wrap_box(s: Box<Inner>) -> Box<Self> {
assert!(size_of::<*mut Inner>() == size_of::<*mut Self>());
unsafe {
let inner_ptr: *mut Inner = Box::into_raw(s);
let wrapper_ptr: *mut Self = transmute!(inner_ptr);
Box::from_raw(wrapper_ptr)
}
}
#[inline]
fn wrap_rc(s: Rc<Inner>) -> Rc<Self> {
assert!(size_of::<*mut Inner>() == size_of::<*mut Self>());
unsafe {
let inner_ptr: *const Inner = Rc::into_raw(s);
let wrapper_ptr: *const Self = transmute!(inner_ptr);
Rc::from_raw(wrapper_ptr)
}
}
#[inline]
#[cfg(target_has_atomic = "ptr")]
fn wrap_arc(s: Arc<Inner>) -> Arc<Self> {
assert!(size_of::<*mut Inner>() == size_of::<*mut Self>());
unsafe {
let inner_ptr: *const Inner = Arc::into_raw(s);
let wrapper_ptr: *const Self = transmute!(inner_ptr);
Arc::from_raw(wrapper_ptr)
}
}
fn peel_vec(s: Vec<Self>) -> Vec<Inner>
where
Self: Sized,
Inner: Sized,
{
let mut s = ManuallyDrop::new(s);
let length = s.len();
let capacity = s.capacity();
let ptr = s.as_mut_ptr();
unsafe {
Vec::from_raw_parts(ptr as *mut Inner, length, capacity)
}
}
#[inline]
fn peel_box(s: Box<Self>) -> Box<Inner> {
assert!(size_of::<*mut Inner>() == size_of::<*mut Self>());
unsafe {
let wrapper_ptr: *mut Self = Box::into_raw(s);
let inner_ptr: *mut Inner = transmute!(wrapper_ptr);
Box::from_raw(inner_ptr)
}
}
#[inline]
fn peel_rc(s: Rc<Self>) -> Rc<Inner> {
assert!(size_of::<*mut Inner>() == size_of::<*mut Self>());
unsafe {
let wrapper_ptr: *const Self = Rc::into_raw(s);
let inner_ptr: *const Inner = transmute!(wrapper_ptr);
Rc::from_raw(inner_ptr)
}
}
#[inline]
#[cfg(target_has_atomic = "ptr")]
fn peel_arc(s: Arc<Self>) -> Arc<Inner> {
assert!(size_of::<*mut Inner>() == size_of::<*mut Self>());
unsafe {
let wrapper_ptr: *const Self = Arc::into_raw(s);
let inner_ptr: *const Inner = transmute!(wrapper_ptr);
Arc::from_raw(inner_ptr)
}
}
}
impl<I: ?Sized, T: ?Sized + TransparentWrapper<I>> TransparentWrapperAlloc<I>
for T
{
}
pub struct BoxBytes {
ptr: NonNull<u8>,
layout: Layout,
}
unsafe impl Send for BoxBytes {}
unsafe impl Sync for BoxBytes {}
impl Deref for BoxBytes {
type Target = [u8];
fn deref(&self) -> &Self::Target {
unsafe {
core::slice::from_raw_parts(self.ptr.as_ptr(), self.layout.size())
}
}
}
impl DerefMut for BoxBytes {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe {
core::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.layout.size())
}
}
}
impl Drop for BoxBytes {
fn drop(&mut self) {
if self.layout.size() != 0 {
unsafe { alloc::alloc::dealloc(self.ptr.as_ptr(), self.layout) };
}
}
}
impl<T: ?Sized + sealed::BoxBytesOf> From<Box<T>> for BoxBytes {
fn from(value: Box<T>) -> Self {
value.box_bytes_of()
}
}
mod sealed {
use crate::{BoxBytes, PodCastError};
use alloc::boxed::Box;
pub trait BoxBytesOf {
fn box_bytes_of(self: Box<Self>) -> BoxBytes;
}
pub trait FromBoxBytes {
fn try_from_box_bytes(
bytes: BoxBytes,
) -> Result<Box<Self>, (PodCastError, BoxBytes)>;
}
}
impl<T: NoUninit> sealed::BoxBytesOf for T {
fn box_bytes_of(self: Box<Self>) -> BoxBytes {
let layout = Layout::new::<T>();
let ptr = Box::into_raw(self) as *mut u8;
let ptr = unsafe { NonNull::new_unchecked(ptr) };
BoxBytes { ptr, layout }
}
}
impl<T: NoUninit> sealed::BoxBytesOf for [T] {
fn box_bytes_of(self: Box<Self>) -> BoxBytes {
let layout = Layout::for_value::<[T]>(&self);
let ptr = Box::into_raw(self) as *mut u8;
let ptr = unsafe { NonNull::new_unchecked(ptr) };
BoxBytes { ptr, layout }
}
}
impl sealed::BoxBytesOf for str {
fn box_bytes_of(self: Box<Self>) -> BoxBytes {
self.into_boxed_bytes().box_bytes_of()
}
}
impl<T: AnyBitPattern> sealed::FromBoxBytes for T {
fn try_from_box_bytes(
bytes: BoxBytes,
) -> Result<Box<Self>, (PodCastError, BoxBytes)> {
let layout = Layout::new::<T>();
if bytes.layout.align() != layout.align() {
Err((PodCastError::AlignmentMismatch, bytes))
} else if bytes.layout.size() != layout.size() {
Err((PodCastError::SizeMismatch, bytes))
} else {
let (ptr, _) = bytes.into_raw_parts();
Ok(unsafe { Box::from_raw(ptr.as_ptr() as *mut T) })
}
}
}
impl<T: AnyBitPattern> sealed::FromBoxBytes for [T] {
fn try_from_box_bytes(
bytes: BoxBytes,
) -> Result<Box<Self>, (PodCastError, BoxBytes)> {
let single_layout = Layout::new::<T>();
if bytes.layout.align() != single_layout.align() {
Err((PodCastError::AlignmentMismatch, bytes))
} else if (single_layout.size() == 0 && bytes.layout.size() != 0)
|| (single_layout.size() != 0
&& bytes.layout.size() % single_layout.size() != 0)
{
Err((PodCastError::OutputSliceWouldHaveSlop, bytes))
} else {
let (ptr, layout) = bytes.into_raw_parts();
let length = if single_layout.size() != 0 {
layout.size() / single_layout.size()
} else {
0
};
let ptr =
core::ptr::slice_from_raw_parts_mut(ptr.as_ptr() as *mut T, length);
Ok(unsafe { Box::from_raw(ptr) })
}
}
}
#[inline]
pub fn box_bytes_of<T: sealed::BoxBytesOf + ?Sized>(input: Box<T>) -> BoxBytes {
input.box_bytes_of()
}
#[inline]
#[cfg_attr(feature = "track_caller", track_caller)]
pub fn from_box_bytes<T: sealed::FromBoxBytes + ?Sized>(
input: BoxBytes,
) -> Box<T> {
try_from_box_bytes(input).map_err(|(error, _)| error).unwrap()
}
#[inline]
pub fn try_from_box_bytes<T: sealed::FromBoxBytes + ?Sized>(
input: BoxBytes,
) -> Result<Box<T>, (PodCastError, BoxBytes)> {
T::try_from_box_bytes(input)
}
impl BoxBytes {
pub unsafe fn from_raw_parts(ptr: NonNull<u8>, layout: Layout) -> Self {
BoxBytes { ptr, layout }
}
pub fn into_raw_parts(self) -> (NonNull<u8>, Layout) {
let me = ManuallyDrop::new(self);
(me.ptr, me.layout)
}
pub fn layout(&self) -> Layout {
self.layout
}
}