| #![cfg(feature = "extern_crate_alloc")] | |
| #![allow(clippy::duplicated_attributes)] | |
| //! Stuff to boost things in the `alloc` crate. | |
| //! | |
| //! * You must enable the `extern_crate_alloc` feature of `bytemuck` or you will | |
| //! not be able to use this module! This is generally done by adding the | |
| //! feature to the dependency in Cargo.toml like so: | |
| //! | |
| //! `bytemuck = { version = "VERSION_YOU_ARE_USING", features = | |
| //! ["extern_crate_alloc"]}` | |
| 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}, | |
| }; | |
| /// As [`try_cast_box`], but unwraps for you. | |
| #[inline] | |
| pub fn cast_box<A: NoUninit, B: AnyBitPattern>(input: Box<A>) -> Box<B> { | |
| try_cast_box(input).map_err(|(e, _v)| e).unwrap() | |
| } | |
| /// Attempts to cast the content type of a [`Box`]. | |
| /// | |
| /// On failure you get back an error along with the starting `Box`. | |
| /// | |
| /// ## Failure | |
| /// | |
| /// * The start and end content type of the `Box` must have the exact same | |
| /// alignment. | |
| /// * The start and end size of the `Box` must have the exact same size. | |
| #[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 { | |
| // Note(Lokathor): This is much simpler than with the Vec casting! | |
| let ptr: *mut B = Box::into_raw(input) as *mut B; | |
| Ok(unsafe { Box::from_raw(ptr) }) | |
| } | |
| } | |
| /// Allocates a `Box<T>` with all of the contents being zeroed out. | |
| /// | |
| /// This uses the global allocator to create a zeroed allocation and _then_ | |
| /// turns it into a Box. In other words, it's 100% assured that the zeroed data | |
| /// won't be put temporarily on the stack. You can make a box of any size | |
| /// without fear of a stack overflow. | |
| /// | |
| /// ## Failure | |
| /// | |
| /// This fails if the allocation fails. | |
| #[inline] | |
| pub fn try_zeroed_box<T: Zeroable>() -> Result<Box<T>, ()> { | |
| if size_of::<T>() == 0 { | |
| // This will not allocate but simply create an arbitrary non-null | |
| // aligned pointer, valid for Box for a zero-sized pointee. | |
| 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() { | |
| // we don't know what the error is because `alloc_zeroed` is a dumb API | |
| Err(()) | |
| } else { | |
| Ok(unsafe { Box::<T>::from_raw(ptr as *mut T) }) | |
| } | |
| } | |
| /// As [`try_zeroed_box`], but unwraps for you. | |
| #[inline] | |
| pub fn zeroed_box<T: Zeroable>() -> Box<T> { | |
| try_zeroed_box().unwrap() | |
| } | |
| /// Allocates a `Vec<T>` of length and capacity exactly equal to `length` and | |
| /// all elements zeroed. | |
| /// | |
| /// ## Failure | |
| /// | |
| /// This fails if the allocation fails, or if a layout cannot be calculated for | |
| /// the allocation. | |
| 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()) | |
| } | |
| } | |
| /// As [`try_zeroed_vec`] but unwraps for you | |
| pub fn zeroed_vec<T: Zeroable>(length: usize) -> Vec<T> { | |
| try_zeroed_vec(length).unwrap() | |
| } | |
| /// Allocates a `Box<[T]>` with all contents being zeroed out. | |
| /// | |
| /// This uses the global allocator to create a zeroed allocation and _then_ | |
| /// turns it into a Box. In other words, it's 100% assured that the zeroed data | |
| /// won't be put temporarily on the stack. You can make a box of any size | |
| /// without fear of a stack overflow. | |
| /// | |
| /// ## Failure | |
| /// | |
| /// This fails if the allocation fails, or if a layout cannot be calculated for | |
| /// the allocation. | |
| #[inline] | |
| pub fn try_zeroed_slice_box<T: Zeroable>( | |
| length: usize, | |
| ) -> Result<Box<[T]>, ()> { | |
| if size_of::<T>() == 0 || length == 0 { | |
| // This will not allocate but simply create an arbitrary non-null aligned | |
| // slice pointer, valid for Box for a zero-sized pointee. | |
| 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() { | |
| // we don't know what the error is because `alloc_zeroed` is a dumb API | |
| Err(()) | |
| } else { | |
| let slice = | |
| unsafe { core::slice::from_raw_parts_mut(ptr as *mut T, length) }; | |
| Ok(unsafe { Box::<[T]>::from_raw(slice) }) | |
| } | |
| } | |
| /// As [`try_zeroed_slice_box`], but unwraps for you. | |
| pub fn zeroed_slice_box<T: Zeroable>(length: usize) -> Box<[T]> { | |
| try_zeroed_slice_box(length).unwrap() | |
| } | |
| /// As [`try_cast_slice_box`], but unwraps for you. | |
| #[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() | |
| } | |
| /// Attempts to cast the content type of a `Box<[T]>`. | |
| /// | |
| /// On failure you get back an error along with the starting `Box<[T]>`. | |
| /// | |
| /// ## Failure | |
| /// | |
| /// * The start and end content type of the `Box<[T]>` must have the exact same | |
| /// alignment. | |
| /// * The start and end content size in bytes of the `Box<[T]>` must be the | |
| /// exact same. | |
| #[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) | |
| { | |
| // If the size in bytes of the underlying buffer does not match an exact | |
| // multiple of the size of B, we cannot cast between them. | |
| Err((PodCastError::OutputSliceWouldHaveSlop, input)) | |
| } else { | |
| // Because the size is an exact multiple, we can now change the length | |
| // of the slice and recreate the Box | |
| // NOTE: This is a valid operation because according to the docs of | |
| // std::alloc::GlobalAlloc::dealloc(), the Layout that was used to alloc | |
| // the block must be the same Layout that is used to dealloc the block. | |
| // Luckily, Layout only stores two things, the alignment, and the size in | |
| // bytes. So as long as both of those stay the same, the Layout will | |
| // remain a valid input to dealloc. | |
| 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) }) | |
| } | |
| } | |
| /// As [`try_cast_vec`], but unwraps for you. | |
| #[inline] | |
| pub fn cast_vec<A: NoUninit, B: AnyBitPattern>(input: Vec<A>) -> Vec<B> { | |
| try_cast_vec(input).map_err(|(e, _v)| e).unwrap() | |
| } | |
| /// Attempts to cast the content type of a [`Vec`]. | |
| /// | |
| /// On failure you get back an error along with the starting `Vec`. | |
| /// | |
| /// ## Failure | |
| /// | |
| /// * The start and end content type of the `Vec` must have the exact same | |
| /// alignment. | |
| /// * The start and end content size in bytes of the `Vec` must be the exact | |
| /// same. | |
| /// * The start and end capacity in bytes of the `Vec` must be the exact same. | |
| #[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)) | |
| { | |
| // If the size in bytes of the underlying buffer does not match an exact | |
| // multiple of the size of B, we cannot cast between them. | |
| // Note that we have to pay special attention to make sure that both | |
| // length and capacity are valid under B, as we do not want to | |
| // change which bytes are considered part of the initialized slice | |
| // of the Vec | |
| Err((PodCastError::OutputSliceWouldHaveSlop, input)) | |
| } else { | |
| // Because the size is an exact multiple, we can now change the length and | |
| // capacity and recreate the Vec | |
| // NOTE: This is a valid operation because according to the docs of | |
| // std::alloc::GlobalAlloc::dealloc(), the Layout that was used to alloc | |
| // the block must be the same Layout that is used to dealloc the block. | |
| // Luckily, Layout only stores two things, the alignment, and the size in | |
| // bytes. So as long as both of those stay the same, the Layout will | |
| // remain a valid input to dealloc. | |
| // Note(Lokathor): First we record the length and capacity, which don't | |
| // have any secret provenance metadata. | |
| 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 }; | |
| // Note(Lokathor): Next we "pre-forget" the old Vec by wrapping with | |
| // ManuallyDrop, because if we used `core::mem::forget` after taking the | |
| // pointer then that would invalidate our pointer. In nightly there's a | |
| // "into raw parts" method, which we can switch this too eventually. | |
| 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 { | |
| // Note(Lokathor): First we record the length and capacity, which don't have | |
| // any secret provenance metadata. | |
| let length: usize = input.len(); | |
| let capacity: usize = input.capacity(); | |
| // Note(Lokathor): Next we "pre-forget" the old Vec by wrapping with | |
| // ManuallyDrop, because if we used `core::mem::forget` after taking the | |
| // pointer then that would invalidate our pointer. In nightly there's a | |
| // "into raw parts" method, which we can switch this too eventually. | |
| 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) }) | |
| } | |
| } | |
| /// This "collects" a slice of pod data into a vec of a different pod type. | |
| /// | |
| /// Unlike with [`cast_slice`] and [`cast_slice_mut`], this will always work. | |
| /// | |
| /// The output vec will be of a minimal size/capacity to hold the slice given. | |
| /// | |
| /// ```rust | |
| /// # use bytemuck::*; | |
| /// let halfwords: [u16; 4] = [5, 6, 7, 8]; | |
| /// let vec_of_words: Vec<u32> = pod_collect_to_vec(&halfwords); | |
| /// if cfg!(target_endian = "little") { | |
| /// assert_eq!(&vec_of_words[..], &[0x0006_0005, 0x0008_0007][..]) | |
| /// } else { | |
| /// assert_eq!(&vec_of_words[..], &[0x0005_0006, 0x0007_0008][..]) | |
| /// } | |
| /// ``` | |
| pub fn pod_collect_to_vec<A: NoUninit, B: NoUninit + AnyBitPattern>( | |
| src: &[A], | |
| ) -> Vec<B> { | |
| let src_size = core::mem::size_of_val(src); | |
| // Note(Lokathor): dst_count is rounded up so that the dest will always be at | |
| // least as many bytes as the 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 | |
| } | |
| /// As [`try_cast_rc`], but unwraps for you. | |
| #[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() | |
| } | |
| /// Attempts to cast the content type of a [`Rc`]. | |
| /// | |
| /// On failure you get back an error along with the starting `Rc`. | |
| /// | |
| /// The bounds on this function are the same as [`cast_mut`], because a user | |
| /// could call `Rc::get_unchecked_mut` on the output, which could be observable | |
| /// in the input. | |
| /// | |
| /// ## Failure | |
| /// | |
| /// * The start and end content type of the `Rc` must have the exact same | |
| /// alignment. | |
| /// * The start and end size of the `Rc` must have the exact same size. | |
| #[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 { | |
| // Safety: Rc::from_raw requires size and alignment match, which is met. | |
| let ptr: *const B = Rc::into_raw(input) as *const B; | |
| Ok(unsafe { Rc::from_raw(ptr) }) | |
| } | |
| } | |
| /// As [`try_cast_arc`], but unwraps for you. | |
| #[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() | |
| } | |
| /// Attempts to cast the content type of a [`Arc`]. | |
| /// | |
| /// On failure you get back an error along with the starting `Arc`. | |
| /// | |
| /// The bounds on this function are the same as [`cast_mut`], because a user | |
| /// could call `Rc::get_unchecked_mut` on the output, which could be observable | |
| /// in the input. | |
| /// | |
| /// ## Failure | |
| /// | |
| /// * The start and end content type of the `Arc` must have the exact same | |
| /// alignment. | |
| /// * The start and end size of the `Arc` must have the exact same size. | |
| #[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 { | |
| // Safety: Arc::from_raw requires size and alignment match, which is met. | |
| let ptr: *const B = Arc::into_raw(input) as *const B; | |
| Ok(unsafe { Arc::from_raw(ptr) }) | |
| } | |
| } | |
| /// As [`try_cast_slice_rc`], but unwraps for you. | |
| #[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() | |
| } | |
| /// Attempts to cast the content type of a `Rc<[T]>`. | |
| /// | |
| /// On failure you get back an error along with the starting `Rc<[T]>`. | |
| /// | |
| /// The bounds on this function are the same as [`cast_mut`], because a user | |
| /// could call `Rc::get_unchecked_mut` on the output, which could be observable | |
| /// in the input. | |
| /// | |
| /// ## Failure | |
| /// | |
| /// * The start and end content type of the `Rc<[T]>` must have the exact same | |
| /// alignment. | |
| /// * The start and end content size in bytes of the `Rc<[T]>` must be the exact | |
| /// same. | |
| #[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) | |
| { | |
| // If the size in bytes of the underlying buffer does not match an exact | |
| // multiple of the size of B, we cannot cast between them. | |
| Err((PodCastError::OutputSliceWouldHaveSlop, input)) | |
| } else { | |
| // Because the size is an exact multiple, we can now change the length | |
| // of the slice and recreate the Rc | |
| // NOTE: This is a valid operation because according to the docs of | |
| // std::rc::Rc::from_raw(), the type U that was in the original Rc<U> | |
| // acquired from Rc::into_raw() must have the same size alignment and | |
| // size of the type T in the new Rc<T>. So as long as both the size | |
| // and alignment stay the same, the Rc will remain a valid Rc. | |
| 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; | |
| // Must use ptr::slice_from_raw_parts, because we cannot make an | |
| // intermediate const reference, because it has mutable provenance, | |
| // nor an intermediate mutable reference, because it could be aliased. | |
| 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) }) | |
| } | |
| } | |
| /// As [`try_cast_slice_arc`], but unwraps for you. | |
| #[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() | |
| } | |
| /// Attempts to cast the content type of a `Arc<[T]>`. | |
| /// | |
| /// On failure you get back an error along with the starting `Arc<[T]>`. | |
| /// | |
| /// The bounds on this function are the same as [`cast_mut`], because a user | |
| /// could call `Rc::get_unchecked_mut` on the output, which could be observable | |
| /// in the input. | |
| /// | |
| /// ## Failure | |
| /// | |
| /// * The start and end content type of the `Arc<[T]>` must have the exact same | |
| /// alignment. | |
| /// * The start and end content size in bytes of the `Arc<[T]>` must be the | |
| /// exact same. | |
| #[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) | |
| { | |
| // If the size in bytes of the underlying buffer does not match an exact | |
| // multiple of the size of B, we cannot cast between them. | |
| Err((PodCastError::OutputSliceWouldHaveSlop, input)) | |
| } else { | |
| // Because the size is an exact multiple, we can now change the length | |
| // of the slice and recreate the Arc | |
| // NOTE: This is a valid operation because according to the docs of | |
| // std::sync::Arc::from_raw(), the type U that was in the original Arc<U> | |
| // acquired from Arc::into_raw() must have the same size alignment and | |
| // size of the type T in the new Arc<T>. So as long as both the size | |
| // and alignment stay the same, the Arc will remain a valid Arc. | |
| 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; | |
| // Must use ptr::slice_from_raw_parts, because we cannot make an | |
| // intermediate const reference, because it has mutable provenance, | |
| // nor an intermediate mutable reference, because it could be aliased. | |
| 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) }) | |
| } | |
| } | |
| /// An extension trait for `TransparentWrapper` and alloc types. | |
| pub trait TransparentWrapperAlloc<Inner: ?Sized>: | |
| TransparentWrapper<Inner> | |
| { | |
| /// Convert a vec of the inner type into a vec of the wrapper type. | |
| 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 { | |
| // SAFETY: | |
| // * ptr comes from Vec (and will not be double-dropped) | |
| // * the two types have the identical representation | |
| // * the len and capacity fields are valid | |
| Vec::from_raw_parts(ptr as *mut Self, length, capacity) | |
| } | |
| } | |
| /// Convert a box to the inner type into a box to the wrapper | |
| /// type. | |
| #[inline] | |
| fn wrap_box(s: Box<Inner>) -> Box<Self> { | |
| // The unsafe contract requires that these two have | |
| // identical representations, and thus identical pointer metadata. | |
| // Assert that Self and Inner have the same pointer size, | |
| // which is the best we can do to assert their metadata is the same type | |
| // on stable. | |
| assert!(size_of::<*mut Inner>() == size_of::<*mut Self>()); | |
| unsafe { | |
| // A pointer cast doesn't work here because rustc can't tell that | |
| // the vtables match (because of the `?Sized` restriction relaxation). | |
| // A `transmute` doesn't work because the sizes are unspecified. | |
| // | |
| // SAFETY: | |
| // * The unsafe contract requires that pointers to Inner and Self have | |
| // identical representations | |
| // * Box is guaranteed to have representation identical to a (non-null) | |
| // pointer | |
| // * The pointer comes from a box (and thus satisfies all safety | |
| // requirements of Box) | |
| let inner_ptr: *mut Inner = Box::into_raw(s); | |
| let wrapper_ptr: *mut Self = transmute!(inner_ptr); | |
| Box::from_raw(wrapper_ptr) | |
| } | |
| } | |
| /// Convert an [`Rc`] to the inner type into an `Rc` to the wrapper type. | |
| #[inline] | |
| fn wrap_rc(s: Rc<Inner>) -> Rc<Self> { | |
| // The unsafe contract requires that these two have | |
| // identical representations, and thus identical pointer metadata. | |
| // Assert that Self and Inner have the same pointer size, | |
| // which is the best we can do to assert their metadata is the same type | |
| // on stable. | |
| assert!(size_of::<*mut Inner>() == size_of::<*mut Self>()); | |
| unsafe { | |
| // A pointer cast doesn't work here because rustc can't tell that | |
| // the vtables match (because of the `?Sized` restriction relaxation). | |
| // A `transmute` doesn't work because the layout of Rc is unspecified. | |
| // | |
| // SAFETY: | |
| // * The unsafe contract requires that pointers to Inner and Self have | |
| // identical representations, and that the size and alignment of Inner | |
| // and Self are the same, which meets the safety requirements of | |
| // Rc::from_raw | |
| let inner_ptr: *const Inner = Rc::into_raw(s); | |
| let wrapper_ptr: *const Self = transmute!(inner_ptr); | |
| Rc::from_raw(wrapper_ptr) | |
| } | |
| } | |
| /// Convert an [`Arc`] to the inner type into an `Arc` to the wrapper type. | |
| #[inline] | |
| #[cfg(target_has_atomic = "ptr")] | |
| fn wrap_arc(s: Arc<Inner>) -> Arc<Self> { | |
| // The unsafe contract requires that these two have | |
| // identical representations, and thus identical pointer metadata. | |
| // Assert that Self and Inner have the same pointer size, | |
| // which is the best we can do to assert their metadata is the same type | |
| // on stable. | |
| assert!(size_of::<*mut Inner>() == size_of::<*mut Self>()); | |
| unsafe { | |
| // A pointer cast doesn't work here because rustc can't tell that | |
| // the vtables match (because of the `?Sized` restriction relaxation). | |
| // A `transmute` doesn't work because the layout of Arc is unspecified. | |
| // | |
| // SAFETY: | |
| // * The unsafe contract requires that pointers to Inner and Self have | |
| // identical representations, and that the size and alignment of Inner | |
| // and Self are the same, which meets the safety requirements of | |
| // Arc::from_raw | |
| let inner_ptr: *const Inner = Arc::into_raw(s); | |
| let wrapper_ptr: *const Self = transmute!(inner_ptr); | |
| Arc::from_raw(wrapper_ptr) | |
| } | |
| } | |
| /// Convert a vec of the wrapper type into a vec of the inner type. | |
| 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 { | |
| // SAFETY: | |
| // * ptr comes from Vec (and will not be double-dropped) | |
| // * the two types have the identical representation | |
| // * the len and capacity fields are valid | |
| Vec::from_raw_parts(ptr as *mut Inner, length, capacity) | |
| } | |
| } | |
| /// Convert a box to the wrapper type into a box to the inner | |
| /// type. | |
| #[inline] | |
| fn peel_box(s: Box<Self>) -> Box<Inner> { | |
| // The unsafe contract requires that these two have | |
| // identical representations, and thus identical pointer metadata. | |
| // Assert that Self and Inner have the same pointer size, | |
| // which is the best we can do to assert their metadata is the same type | |
| // on stable. | |
| assert!(size_of::<*mut Inner>() == size_of::<*mut Self>()); | |
| unsafe { | |
| // A pointer cast doesn't work here because rustc can't tell that | |
| // the vtables match (because of the `?Sized` restriction relaxation). | |
| // A `transmute` doesn't work because the sizes are unspecified. | |
| // | |
| // SAFETY: | |
| // * The unsafe contract requires that pointers to Inner and Self have | |
| // identical representations | |
| // * Box is guaranteed to have representation identical to a (non-null) | |
| // pointer | |
| // * The pointer comes from a box (and thus satisfies all safety | |
| // requirements of Box) | |
| let wrapper_ptr: *mut Self = Box::into_raw(s); | |
| let inner_ptr: *mut Inner = transmute!(wrapper_ptr); | |
| Box::from_raw(inner_ptr) | |
| } | |
| } | |
| /// Convert an [`Rc`] to the wrapper type into an `Rc` to the inner type. | |
| #[inline] | |
| fn peel_rc(s: Rc<Self>) -> Rc<Inner> { | |
| // The unsafe contract requires that these two have | |
| // identical representations, and thus identical pointer metadata. | |
| // Assert that Self and Inner have the same pointer size, | |
| // which is the best we can do to assert their metadata is the same type | |
| // on stable. | |
| assert!(size_of::<*mut Inner>() == size_of::<*mut Self>()); | |
| unsafe { | |
| // A pointer cast doesn't work here because rustc can't tell that | |
| // the vtables match (because of the `?Sized` restriction relaxation). | |
| // A `transmute` doesn't work because the layout of Rc is unspecified. | |
| // | |
| // SAFETY: | |
| // * The unsafe contract requires that pointers to Inner and Self have | |
| // identical representations, and that the size and alignment of Inner | |
| // and Self are the same, which meets the safety requirements of | |
| // Rc::from_raw | |
| let wrapper_ptr: *const Self = Rc::into_raw(s); | |
| let inner_ptr: *const Inner = transmute!(wrapper_ptr); | |
| Rc::from_raw(inner_ptr) | |
| } | |
| } | |
| /// Convert an [`Arc`] to the wrapper type into an `Arc` to the inner type. | |
| #[inline] | |
| #[cfg(target_has_atomic = "ptr")] | |
| fn peel_arc(s: Arc<Self>) -> Arc<Inner> { | |
| // The unsafe contract requires that these two have | |
| // identical representations, and thus identical pointer metadata. | |
| // Assert that Self and Inner have the same pointer size, | |
| // which is the best we can do to assert their metadata is the same type | |
| // on stable. | |
| assert!(size_of::<*mut Inner>() == size_of::<*mut Self>()); | |
| unsafe { | |
| // A pointer cast doesn't work here because rustc can't tell that | |
| // the vtables match (because of the `?Sized` restriction relaxation). | |
| // A `transmute` doesn't work because the layout of Arc is unspecified. | |
| // | |
| // SAFETY: | |
| // * The unsafe contract requires that pointers to Inner and Self have | |
| // identical representations, and that the size and alignment of Inner | |
| // and Self are the same, which meets the safety requirements of | |
| // Arc::from_raw | |
| 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 | |
| { | |
| } | |
| /// As `Box<[u8]>`, but remembers the original alignment. | |
| pub struct BoxBytes { | |
| // SAFETY: `ptr` is aligned to `layout.align()`, points to | |
| // `layout.size()` initialized bytes, and, if `layout.size() > 0`, | |
| // is owned and was allocated with the global allocator with `layout`. | |
| ptr: NonNull<u8>, | |
| layout: Layout, | |
| } | |
| impl Deref for BoxBytes { | |
| type Target = [u8]; | |
| fn deref(&self) -> &Self::Target { | |
| // SAFETY: See type invariant. | |
| 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 { | |
| // SAFETY: See type invariant. | |
| 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 { | |
| // SAFETY: See type invariant: if `self.layout.size() != 0`, then | |
| // `self.ptr` is owned and was allocated with `self.layout`. | |
| 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; | |
| // SAFETY: Box::into_raw() returns a non-null pointer. | |
| 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; | |
| // SAFETY: Box::into_raw() returns a non-null pointer. | |
| 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(); | |
| // SAFETY: See BoxBytes type invariant. | |
| 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); | |
| // SAFETY: See BoxBytes type invariant. | |
| Ok(unsafe { Box::from_raw(ptr) }) | |
| } | |
| } | |
| } | |
| /// Re-interprets `Box<T>` as `BoxBytes`. | |
| /// | |
| /// `T` must be either [`Sized`] and [`NoUninit`], | |
| /// [`[U]`](slice) where `U: NoUninit`, or [`str`]. | |
| #[inline] | |
| pub fn box_bytes_of<T: sealed::BoxBytesOf + ?Sized>(input: Box<T>) -> BoxBytes { | |
| input.box_bytes_of() | |
| } | |
| /// Re-interprets `BoxBytes` as `Box<T>`. | |
| /// | |
| /// `T` must be either [`Sized`] + [`AnyBitPattern`], or | |
| /// [`[U]`](slice) where `U: AnyBitPattern`. | |
| /// | |
| /// ## Panics | |
| /// | |
| /// This is [`try_from_box_bytes`] but will panic on error and the input will be | |
| /// dropped. | |
| #[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() | |
| } | |
| /// Re-interprets `BoxBytes` as `Box<T>`. | |
| /// | |
| /// `T` must be either [`Sized`] + [`AnyBitPattern`], or | |
| /// [`[U]`](slice) where `U: AnyBitPattern`. | |
| /// | |
| /// Returns `Err`: | |
| /// * If the input isn't aligned for `T`. | |
| /// * If `T: Sized` and the input's length isn't exactly the size of `T`. | |
| /// * If `T = [U]` and the input's length isn't exactly a multiple of the size | |
| /// of `U`. | |
| #[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 { | |
| /// Constructs a `BoxBytes` from its raw parts. | |
| /// | |
| /// # Safety | |
| /// | |
| /// The pointer is owned, has been allocated with the provided layout, and | |
| /// points to `layout.size()` initialized bytes. | |
| pub unsafe fn from_raw_parts(ptr: NonNull<u8>, layout: Layout) -> Self { | |
| BoxBytes { ptr, layout } | |
| } | |
| /// Deconstructs a `BoxBytes` into its raw parts. | |
| /// | |
| /// The pointer is owned, has been allocated with the provided layout, and | |
| /// points to `layout.size()` initialized bytes. | |
| pub fn into_raw_parts(self) -> (NonNull<u8>, Layout) { | |
| let me = ManuallyDrop::new(self); | |
| (me.ptr, me.layout) | |
| } | |
| /// Returns the original layout. | |
| pub fn layout(&self) -> Layout { | |
| self.layout | |
| } | |
| } |