//! 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"]}`
usesuper::*; #[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] pubfn 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] pubfn 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))
} elseif 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] pubfn 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] pubfn 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. pubfn 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 pubfn 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] pubfn 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. pubfn zeroed_slice_box<T: Zeroable>(length: usize) -> Box<[T]> {
try_zeroed_slice_box(length).unwrap()
}
/// Allocates a `Arc<T>` with all contents being zeroed out. #[cfg(all(feature = "alloc_uninit", target_has_atomic = "ptr"))] pubfn zeroed_arc<T: Zeroable>() -> Arc<T> { letmut arc = Arc::new_uninit(); crate::write_zeroes(Arc::get_mut(&mut arc).unwrap()); // unwrap never fails for a newly allocated Arc unsafe { arc.assume_init() }
}
/// Allocates a `Arc<[T]>` with all contents being zeroed out. #[cfg(all(feature = "alloc_uninit", target_has_atomic = "ptr"))] pubfn zeroed_arc_slice<T: Zeroable>(length: usize) -> Arc<[T]> { letmut arc = Arc::new_uninit_slice(length); crate::fill_zeroes(Arc::get_mut(&mut arc).unwrap()); // unwrap never fails for a newly allocated Arc unsafe { arc.assume_init() }
}
/// Allocates a `Rc<T>` with all contents being zeroed out. #[cfg(feature = "alloc_uninit")] pubfn zeroed_rc<T: Zeroable>() -> Rc<T> { letmut rc = Rc::new_uninit(); crate::write_zeroes(Rc::get_mut(&mut rc).unwrap()); // unwrap never fails for a newly allocated Rc unsafe { rc.assume_init() }
}
/// Allocates a `Rc<[T]>` with all contents being zeroed out. #[cfg(feature = "alloc_uninit")] pubfn zeroed_rc_slice<T: Zeroable>(length: usize) -> Rc<[T]> { letmut rc = Rc::new_uninit_slice(length); crate::fill_zeroes(Rc::get_mut(&mut rc).unwrap()); // unwrap never fails for a newly allocated Rc unsafe { rc.assume_init() }
}
/// As [`try_cast_slice_box`], but unwraps for you. #[inline] pubfn 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] pubfn 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))
} elseif 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] pubfn 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] pubfn 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))
} elseif 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. letmut 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. letmut 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][..]) /// } /// ``` pubfn 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 }; letmut 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] pubfn 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] pubfn 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))
} elseif 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")] pubfn 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")] pubfn 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))
} elseif 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] pubfn 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] pubfn 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))
} elseif 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) })
}
}
/// 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")] pubfn 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))
} elseif 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. pubtrait 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,
{ letmut 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 *mutSelf, 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::<*mutSelf>());
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: *mutSelf = 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::<*mutSelf>());
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: *constSelf = 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::<*mutSelf>());
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: *constSelf = 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,
{ letmut 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::<*mutSelf>());
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: *mutSelf = 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::<*mutSelf>());
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: *constSelf = 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::<*mutSelf>());
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: *constSelf = 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. pubstruct 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,
}
// SAFETY: `BoxBytes` is semantically a `Box<[u8], Global>` with a different allocation alignment, // `Box<[u8], Global>` is `Send + Sync`, and changing the allocation alignment has no thread-safety implications. unsafeimpl Send for BoxBytes {} // SAFETY: See `Send` impl unsafeimpl Sync for BoxBytes {}
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(&mutself) -> &mutSelf::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(&mutself) { ifself.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: 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))
} elseif 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))
} elseif (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] pubfn 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)] pubfn 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] pubfn 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. pubunsafefn 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. pubfn into_raw_parts(self) -> (NonNull<u8>, Layout) { let me = ManuallyDrop::new(self);
(me.ptr, me.layout)
}
/// Returns the original layout. pubfn layout(&self) -> Layout { self.layout
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.