mirror of
https://github.com/Lokathor/bytemuck.git
synced 2024-11-21 22:32:23 +00:00
Convert BoxBytes
to/from boxed slices (#228)
* Allow converting BoxBytes to/from boxed slices of NoUninit, and from Box<str>. * Implement From<Box<T>> for BoxBytes generically * Minor cleanup
This commit is contained in:
parent
91bbbdf9a5
commit
a888e5f2c0
@ -727,53 +727,132 @@ impl Drop for BoxBytes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: NoUninit> From<Box<T>> for BoxBytes {
|
impl<T: ?Sized + sealed::BoxBytesOf> From<Box<T>> for BoxBytes {
|
||||||
fn from(value: Box<T>) -> Self {
|
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 layout = Layout::new::<T>();
|
||||||
let ptr = Box::into_raw(value) as *mut u8;
|
let ptr = Box::into_raw(self) as *mut u8;
|
||||||
// SAFETY: Box::into_raw() returns a non-null pointer.
|
// SAFETY: Box::into_raw() returns a non-null pointer.
|
||||||
let ptr = unsafe { NonNull::new_unchecked(ptr) };
|
let ptr = unsafe { NonNull::new_unchecked(ptr) };
|
||||||
BoxBytes { ptr, layout }
|
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 {
|
||||||
|
Err((PodCastError::SizeMismatch, bytes))
|
||||||
|
} else if bytes.layout.size() % single_layout.size() != 0 {
|
||||||
|
Err((PodCastError::OutputSliceWouldHaveSlop, bytes))
|
||||||
|
} else {
|
||||||
|
let (ptr, layout) = bytes.into_raw_parts();
|
||||||
|
let length = layout.size() / single_layout.size();
|
||||||
|
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`.
|
/// Re-interprets `Box<T>` as `BoxBytes`.
|
||||||
|
///
|
||||||
|
/// `T` must be either [`Sized`] and [`NoUninit`],
|
||||||
|
/// [`[U]`](slice) where `U: NoUninit`, or [`str`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn box_bytes_of<T: NoUninit>(input: Box<T>) -> BoxBytes {
|
pub fn box_bytes_of<T: sealed::BoxBytesOf + ?Sized>(input: Box<T>) -> BoxBytes {
|
||||||
input.into()
|
input.box_bytes_of()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Re-interprets `BoxBytes` as `Box<T>`.
|
/// Re-interprets `BoxBytes` as `Box<T>`.
|
||||||
///
|
///
|
||||||
|
/// `T` must be either [`Sized`] + [`AnyBitPattern`], or
|
||||||
|
/// [`[U]`](slice) where `U: AnyBitPattern`.
|
||||||
|
///
|
||||||
/// ## Panics
|
/// ## Panics
|
||||||
///
|
///
|
||||||
/// This is [`try_from_box_bytes`] but will panic on error and the input will be
|
/// This is [`try_from_box_bytes`] but will panic on error and the input will be
|
||||||
/// dropped.
|
/// dropped.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_box_bytes<T: AnyBitPattern>(input: BoxBytes) -> Box<T> {
|
pub fn from_box_bytes<T: sealed::FromBoxBytes + ?Sized>(
|
||||||
|
input: BoxBytes,
|
||||||
|
) -> Box<T> {
|
||||||
try_from_box_bytes(input).map_err(|(error, _)| error).unwrap()
|
try_from_box_bytes(input).map_err(|(error, _)| error).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Re-interprets `BoxBytes` as `Box<T>`.
|
/// Re-interprets `BoxBytes` as `Box<T>`.
|
||||||
///
|
///
|
||||||
/// ## Panics
|
/// `T` must be either [`Sized`] + [`AnyBitPattern`], or
|
||||||
|
/// [`[U]`](slice) where `U: AnyBitPattern`.
|
||||||
///
|
///
|
||||||
/// * If the input isn't aligned for the new type
|
/// Returns `Err`:
|
||||||
/// * If the input's length isn’t exactly the size of the new type
|
/// * 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]
|
#[inline]
|
||||||
pub fn try_from_box_bytes<T: AnyBitPattern>(
|
pub fn try_from_box_bytes<T: sealed::FromBoxBytes + ?Sized>(
|
||||||
input: BoxBytes,
|
input: BoxBytes,
|
||||||
) -> Result<Box<T>, (PodCastError, BoxBytes)> {
|
) -> Result<Box<T>, (PodCastError, BoxBytes)> {
|
||||||
let layout = Layout::new::<T>();
|
T::try_from_box_bytes(input)
|
||||||
if input.layout.align() != layout.align() {
|
|
||||||
return Err((PodCastError::AlignmentMismatch, input));
|
|
||||||
} else if input.layout.size() != layout.size() {
|
|
||||||
return Err((PodCastError::SizeMismatch, input));
|
|
||||||
} else {
|
|
||||||
let (ptr, _) = input.into_raw_parts();
|
|
||||||
// SAFETY: See type invariant.
|
|
||||||
Ok(unsafe { Box::from_raw(ptr.as_ptr() as *mut T) })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BoxBytes {
|
impl BoxBytes {
|
||||||
|
Loading…
Reference in New Issue
Block a user