Skip to content

Commit

Permalink
Add non-slice Ref constructors w/ slice elem count
Browse files Browse the repository at this point in the history
Add `Ref` constructors which are generic over `T:
KnownLayout<PointerMetadata = usize>` - in other words, types whose
trailing field is a slice (i.e., slices or slice DSTs). These
constructors take an explicit element count for the trailing slice, and
replace the previous constructors which only supported slices.

Makes progress on #29
  • Loading branch information
joshlf committed Mar 2, 2024
1 parent b730441 commit e24c207
Showing 1 changed file with 129 additions and 85 deletions.
214 changes: 129 additions & 85 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2521,11 +2521,25 @@ pub unsafe trait FromBytes: FromZeros {
/// assert_eq!(rest, &[8, 9]);
/// ```
#[inline]
fn from_prefix_with_trailing_elements(bytes: &[u8], count: usize) -> Option<(&Self, &[u8])>
where
Self: KnownLayout<PointerMetadata = usize> + NoCell,
{
Ref::<_, Self>::with_trailing_elements_from_prefix(bytes, count)
.map(|(r, b)| (r.into_ref(), b))
}

#[deprecated(
since = "0.8.0",
note = "renamed to `FromBytes::from_prefix_with_trailing_elements`"
)]
#[doc(hidden)]
#[inline]
fn slice_from_prefix(bytes: &[u8], count: usize) -> Option<(&[Self], &[u8])>
where
Self: Sized + NoCell,
{
Ref::<_, [Self]>::new_slice_from_prefix(bytes, count).map(|(r, b)| (r.into_ref(), b))
<[Self]>::from_prefix_with_trailing_elements(bytes, count)
}

/// Interprets the suffix of the given `bytes` as a `&[Self]` with length
Expand Down Expand Up @@ -2572,62 +2586,35 @@ pub unsafe trait FromBytes: FromZeros {
/// ]);
/// ```
#[inline]
fn from_suffix_with_trailing_elements(bytes: &[u8], count: usize) -> Option<(&[u8], &Self)>
where
Self: KnownLayout<PointerMetadata = usize> + NoCell,
{
Ref::<_, Self>::with_trailing_elements_from_suffix(bytes, count)
.map(|(b, r)| (b, r.into_ref()))
}

#[deprecated(
since = "0.8.0",
note = "renamed to `FromBytes::from_prefix_with_trailing_elements`"
)]
#[doc(hidden)]
#[inline]
fn slice_from_suffix(bytes: &[u8], count: usize) -> Option<(&[u8], &[Self])>
where
Self: Sized + NoCell,
{
Ref::<_, [Self]>::new_slice_from_suffix(bytes, count).map(|(b, r)| (b, r.into_ref()))
<[Self]>::from_suffix_with_trailing_elements(bytes, count)
}

/// Interprets the given `bytes` as a `&mut [Self]` without copying.
///
/// If `bytes.len() % size_of::<T>() != 0` or `bytes` is not aligned to
/// `align_of::<T>()`, this returns `None`.
///
/// If you need to convert a specific number of slice elements, see
/// [`mut_slice_from_prefix`](FromBytes::mut_slice_from_prefix) or
/// [`mut_slice_from_suffix`](FromBytes::mut_slice_from_suffix).
///
/// # Panics
///
/// If `T` is a zero-sized type.
///
/// # Examples
///
/// ```
/// use zerocopy::FromBytes;
/// # use zerocopy_derive::*;
///
/// # #[derive(Debug, PartialEq, Eq)]
/// #[derive(FromBytes, IntoBytes, NoCell)]
/// #[repr(C)]
/// struct Pixel {
/// r: u8,
/// g: u8,
/// b: u8,
/// a: u8,
/// }
///
/// // These bytes encode two `Pixel`s.
/// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7][..];
///
/// let pixels = Pixel::mut_slice_from(bytes).unwrap();
///
/// assert_eq!(pixels, &[
/// Pixel { r: 0, g: 1, b: 2, a: 3 },
/// Pixel { r: 4, g: 5, b: 6, a: 7 },
/// ]);
///
/// pixels[1] = Pixel { r: 0, g: 0, b: 0, a: 0 };
///
/// assert_eq!(bytes, [0, 1, 2, 3, 0, 0, 0, 0]);
/// ```
#[deprecated(since = "0.8.0", note = "`FromBytes::mut_from` now supports slices")]
#[doc(hidden)]
#[inline]
fn mut_slice_from(bytes: &mut [u8]) -> Option<&mut [Self]>
where
Self: Sized + IntoBytes + NoCell,
{
Ref::<_, [Self]>::new(bytes).map(|r| r.into_mut())
<[Self]>::mut_from(bytes)
}

/// Interprets the prefix of the given `bytes` as a `&mut [Self]` with length
Expand Down Expand Up @@ -2678,11 +2665,28 @@ pub unsafe trait FromBytes: FromZeros {
/// assert_eq!(bytes, [0, 1, 2, 3, 0, 0, 0, 0, 8, 9]);
/// ```
#[inline]
fn mut_slice_from_prefix(bytes: &mut [u8], count: usize) -> Option<(&mut [Self], &mut [u8])>
fn mut_from_prefix_with_trailing_elements(
bytes: &mut [u8],
count: usize,
) -> Option<(&mut Self, &mut [u8])>
where
Self: Sized + IntoBytes + NoCell,
Self: IntoBytes + KnownLayout<PointerMetadata = usize> + NoCell,
{
Ref::<_, Self>::with_trailing_elements_from_prefix(bytes, count)
.map(|(r, b)| (r.into_mut(), b))
}

#[deprecated(
since = "0.8.0",
note = "renamed to `FromBytes::mut_from_prefix_with_trailing_elements`"
)]
#[doc(hidden)]
#[inline]
fn mut_slice_from_prefix(bytes: &[u8], count: usize) -> Option<(&[Self], &[u8])>
where
Self: Sized + NoCell,
{
Ref::<_, [Self]>::new_slice_from_prefix(bytes, count).map(|(r, b)| (r.into_mut(), b))
<[Self]>::from_prefix_with_trailing_elements(bytes, count)
}

/// Interprets the suffix of the given `bytes` as a `&mut [Self]` with length
Expand Down Expand Up @@ -2733,11 +2737,28 @@ pub unsafe trait FromBytes: FromZeros {
/// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 0, 0, 0, 0]);
/// ```
#[inline]
fn mut_from_suffix_with_trailing_elements(
bytes: &mut [u8],
count: usize,
) -> Option<(&mut [u8], &mut Self)>
where
Self: IntoBytes + KnownLayout<PointerMetadata = usize> + NoCell,
{
Ref::<_, Self>::with_trailing_elements_from_suffix(bytes, count)
.map(|(b, r)| (b, r.into_mut()))
}

#[deprecated(
since = "0.8.0",
note = "renamed to `FromBytes::mut_from_suffix_with_trailing_elements`"
)]
#[doc(hidden)]
#[inline]
fn mut_slice_from_suffix(bytes: &mut [u8], count: usize) -> Option<(&mut [u8], &mut [Self])>
where
Self: Sized + IntoBytes + NoCell,
{
Ref::<_, [Self]>::new_slice_from_suffix(bytes, count).map(|(b, r)| (b, r.into_mut()))
<[Self]>::mut_from_suffix_with_trailing_elements(bytes, count)
}

/// Reads a copy of `Self` from `bytes`.
Expand Down Expand Up @@ -5061,39 +5082,34 @@ where
}
}

impl<B, T> Ref<B, [T]>
impl<B, T> Ref<B, T>
where
B: ByteSlice,
T: NoCell,
B: SplitByteSlice,
T: KnownLayout<PointerMetadata = usize> + NoCell + ?Sized,
{
#[deprecated(since = "0.8.0", note = "`Ref::new` now supports slices")]
#[doc(hidden)]
#[inline]
pub fn new_slice(bytes: B) -> Option<Ref<B, [T]>> {
pub fn with_trailing_elements(bytes: B, count: usize) -> Option<Ref<B, T>> {
let expected_len = match count.size_for_metadata(T::LAYOUT) {
Some(len) => len,
None => return None,
};
if bytes.len() != expected_len {
return None;
}
Self::new(bytes)
}
}

impl<B, T> Ref<B, [T]>
impl<B, T> Ref<B, T>
where
B: SplitByteSlice,
T: NoCell,
T: KnownLayout<PointerMetadata = usize> + NoCell + ?Sized,
{
/// Constructs a new `Ref` of a slice type from the prefix of a byte slice.
///
/// `new_slice_from_prefix` verifies that `bytes.len() >= size_of::<T>() *
/// count` and that `bytes` is aligned to `align_of::<T>()`. It consumes the
/// first `size_of::<T>() * count` bytes from `bytes` to construct a `Ref`,
/// and returns the remaining bytes to the caller. It also ensures that
/// `sizeof::<T>() * count` does not overflow a `usize`. If any of the
/// length, alignment, or overflow checks fail, it returns `None`.
///
/// # Panics
///
/// `new_slice_from_prefix` panics if `T` is a zero-sized type.
#[doc(hidden)]
#[inline]
pub fn new_slice_from_prefix(bytes: B, count: usize) -> Option<(Ref<B, [T]>, B)> {
let expected_len = match mem::size_of::<T>().checked_mul(count) {
pub fn with_trailing_elements_from_prefix(bytes: B, count: usize) -> Option<(Ref<B, T>, B)> {
let expected_len = match count.size_for_metadata(T::LAYOUT) {
Some(len) => len,
None => return None,
};
Expand All @@ -5103,22 +5119,17 @@ where
let (prefix, bytes) = bytes.split_at(expected_len);
Self::new(prefix).map(move |l| (l, bytes))
}
}

/// Constructs a new `Ref` of a slice type from the suffix of a byte slice.
///
/// `new_slice_from_suffix` verifies that `bytes.len() >= size_of::<T>() *
/// count` and that `bytes` is aligned to `align_of::<T>()`. It consumes the
/// last `size_of::<T>() * count` bytes from `bytes` to construct a `Ref`,
/// and returns the preceding bytes to the caller. It also ensures that
/// `sizeof::<T>() * count` does not overflow a `usize`. If any of the
/// length, alignment, or overflow checks fail, it returns `None`.
///
/// # Panics
///
/// `new_slice_from_suffix` panics if `T` is a zero-sized type.
impl<B, T> Ref<B, T>
where
B: SplitByteSlice,
T: KnownLayout<PointerMetadata = usize> + NoCell + ?Sized,
{
#[doc(hidden)]
#[inline]
pub fn new_slice_from_suffix(bytes: B, count: usize) -> Option<(B, Ref<B, [T]>)> {
let expected_len = match mem::size_of::<T>().checked_mul(count) {
pub fn with_trailing_elements_from_suffix(bytes: B, count: usize) -> Option<(B, Ref<B, T>)> {
let expected_len = match count.size_for_metadata(T::LAYOUT) {
Some(len) => len,
None => return None,
};
Expand All @@ -5128,6 +5139,39 @@ where
}
}

impl<B, T> Ref<B, [T]>
where
B: ByteSlice,
T: NoCell,
{
#[deprecated(since = "0.8.0", note = "`Ref::new` now supports slices")]
#[doc(hidden)]
#[inline]
pub fn new_slice(bytes: B) -> Option<Ref<B, [T]>> {
Self::new(bytes)
}
}

impl<B, T> Ref<B, [T]>
where
B: SplitByteSlice,
T: NoCell,
{
#[deprecated(since = "0.8.0", note = "replaced by `Ref::with_trailing_elements_from_prefix`")]
#[doc(hidden)]
#[inline]
pub fn new_slice_from_prefix(bytes: B, count: usize) -> Option<(Ref<B, [T]>, B)> {
Ref::with_trailing_elements_from_prefix(bytes, count)
}

#[deprecated(since = "0.8.0", note = "replaced by `Ref::with_trailing_elements_from_suffix`")]
#[doc(hidden)]
#[inline]
pub fn new_slice_from_suffix(bytes: B, count: usize) -> Option<(B, Ref<B, [T]>)> {
Ref::with_trailing_elements_from_suffix(bytes, count)
}
}

fn map_zeroed<B: ByteSliceMut, T: ?Sized>(opt: Option<Ref<B, T>>) -> Option<Ref<B, T>> {
match opt {
Some(mut r) => {
Expand Down

0 comments on commit e24c207

Please sign in to comment.