Simplify try_zeroed_box and try_zeroed_slice_box (#162)

This commit is contained in:
Alphyr 2023-01-19 21:33:27 +01:00 committed by GitHub
parent 2548e460cb
commit fa5e5dd1d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -19,7 +19,6 @@ use alloc::{
vec, vec,
vec::Vec, vec::Vec,
}; };
use core::convert::TryInto;
/// As [`try_cast_box`](try_cast_box), but unwraps for you. /// As [`try_cast_box`](try_cast_box), but unwraps for you.
#[inline] #[inline]
@ -64,23 +63,11 @@ pub fn try_cast_box<A: NoUninit, B: AnyBitPattern>(
#[inline] #[inline]
pub fn try_zeroed_box<T: Zeroable>() -> Result<Box<T>, ()> { pub fn try_zeroed_box<T: Zeroable>() -> Result<Box<T>, ()> {
if size_of::<T>() == 0 { if size_of::<T>() == 0 {
// This will not allocate but simple create a dangling slice pointer. // This will not allocate but simply create a dangling pointer.
// NB: We go the way via a push to `Vec<T>` to ensure the compiler let dangling = core::ptr::NonNull::dangling().as_ptr();
// does not allocate space for T on the stack even if the branch return Ok(unsafe { Box::from_raw(dangling) });
// would not be taken.
let mut vec = Vec::with_capacity(1);
vec.resize_with(1, || T::zeroed());
let ptr: Box<[T; 1]> = vec.into_boxed_slice().try_into().ok().unwrap();
debug_assert!(
align_of::<[T; 1]>() == align_of::<T>()
&& size_of::<[T; 1]>() == size_of::<T>()
);
// NB: We basically do the same as in try_cast_box here:
let ptr: Box<T> = unsafe { Box::from_raw(Box::into_raw(ptr) as *mut _) };
return Ok(ptr);
} }
let layout = let layout = Layout::new::<T>();
Layout::from_size_align(size_of::<T>(), align_of::<T>()).unwrap();
let ptr = unsafe { alloc_zeroed(layout) }; let ptr = unsafe { alloc_zeroed(layout) };
if ptr.is_null() { if ptr.is_null() {
// we don't know what the error is because `alloc_zeroed` is a dumb API // we don't know what the error is because `alloc_zeroed` is a dumb API
@ -132,15 +119,11 @@ pub fn zeroed_vec<T: Zeroable>(length: usize) -> Vec<T> {
pub fn try_zeroed_slice_box<T: Zeroable>( pub fn try_zeroed_slice_box<T: Zeroable>(
length: usize, length: usize,
) -> Result<Box<[T]>, ()> { ) -> Result<Box<[T]>, ()> {
if size_of::<T>() == 0 { if size_of::<T>() == 0 || length == 0 {
// This will not allocate but simple create a dangling slice pointer. // This will not allocate but simply create a dangling slice pointer.
let mut vec = Vec::with_capacity(length); let dangling = core::ptr::NonNull::dangling().as_ptr();
vec.resize_with(length, || T::zeroed()); let dangling_slice = core::ptr::slice_from_raw_parts_mut(dangling, length);
return Ok(vec.into_boxed_slice()); return Ok(unsafe { Box::from_raw(dangling_slice) });
}
if length == 0 {
// This will also not allocate.
return Ok(Vec::new().into_boxed_slice());
} }
let layout = core::alloc::Layout::array::<T>(length).map_err(|_| ())?; let layout = core::alloc::Layout::array::<T>(length).map_err(|_| ())?;
let ptr = unsafe { alloc_zeroed(layout) }; let ptr = unsafe { alloc_zeroed(layout) };