Skip to content

Commit

Permalink
FromZeros boxed slice method supports slice DSTs
Browse files Browse the repository at this point in the history
Makes progress on #29
  • Loading branch information
joshlf committed Sep 7, 2024
1 parent 02dc876 commit 35043ae
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 18 deletions.
4 changes: 4 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,10 @@ impl<Src, Dst: ?Sized + TryFromBytes> TryReadError<Src, Dst> {
}
}

/// The error type of a failed allocation.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct AllocError;

#[cfg(test)]
mod tests {
use super::*;
Expand Down
37 changes: 19 additions & 18 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2189,14 +2189,16 @@ pub unsafe trait FromZeros: TryFromBytes {
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
#[inline]
fn new_box_slice_zeroed(len: usize) -> Box<[Self]>
fn new_box_zeroed_with_elems(count: usize) -> Option<Box<Self>>
where
Self: Sized,
Self: KnownLayout<PointerMetadata = usize>,
{
let size = mem::size_of::<Self>()
.checked_mul(len)
.expect("mem::size_of::<Self>() * len overflows `usize`");
let align = mem::align_of::<Self>();
let size = match count.size_for_metadata(Self::LAYOUT) {
Some(size) => size,
None => return None,
};

let align = Self::LAYOUT.align.get();
// On stable Rust versions <= 1.64.0, `Layout::from_size_align` has a
// bug in which sufficiently-large allocations (those which, when
// rounded up to the alignment, overflow `isize`) are not rejected,
Expand All @@ -2208,29 +2210,28 @@ pub unsafe trait FromZeros: TryFromBytes {
assert!(size <= max_alloc);
// TODO(https://github.com/rust-lang/rust/issues/55724): Use
// `Layout::repeat` once it's stabilized.
let layout =
Layout::from_size_align(size, align).expect("total allocation size overflows `isize`");
let layout = Layout::from_size_align(size, align).ok()?;

let ptr = if layout.size() != 0 {
// TODO(#429): Add a "SAFETY" comment and remove this `allow`.
#[allow(clippy::undocumented_unsafe_blocks)]
let ptr = unsafe { alloc::alloc::alloc_zeroed(layout).cast::<Self>() };
if ptr.is_null() {
alloc::alloc::handle_alloc_error(layout);
let ptr = unsafe { alloc::alloc::alloc_zeroed(layout) };
match NonNull::new(ptr) {
Some(ptr) => ptr,
None => alloc::alloc::handle_alloc_error(layout),
}
ptr
} else {
// `Box<[T]>` does not allocate when `T` is zero-sized or when `len`
// is zero, but it does require a non-null dangling pointer for its
// allocation.
NonNull::<Self>::dangling().as_ptr()
NonNull::<u8>::dangling()
};

let ptr = Self::raw_from_ptr_len(ptr, count);

// TODO(#429): Add a "SAFETY" comment and remove this `allow`.
#[allow(clippy::undocumented_unsafe_blocks)]
unsafe {
Box::from_raw(slice::from_raw_parts_mut(ptr, len))
}
Some(unsafe { Box::from_raw(ptr.as_ptr()) })
}

/// Creates a `Vec<Self>` from zeroed bytes.
Expand All @@ -2257,11 +2258,11 @@ pub unsafe trait FromZeros: TryFromBytes {
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
#[inline(always)]
fn new_vec_zeroed(len: usize) -> Vec<Self>
fn new_vec_zeroed(len: usize) -> Result<Vec<Self>, AllocError>
where
Self: Sized,
{
Self::new_box_slice_zeroed(len).into()
<[Self]>::new_box_zeroed_with_elems(len).map(Into::into).ok_or(AllocError)
}
}

Expand Down

0 comments on commit 35043ae

Please sign in to comment.