Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Also return remaining bytes in FromBytes conversion methods #1059

Merged
merged 1 commit into from
Apr 23, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
162 changes: 85 additions & 77 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2203,12 +2203,10 @@ pub unsafe trait FromBytes: FromZeros {

/// Interprets the prefix of the given `bytes` as a `&Self` without copying.
///
/// `ref_from_prefix` returns a reference to the first `size_of::<Self>()`
/// bytes of `bytes`. If `bytes.len() < size_of::<Self>()` or `bytes` is not
/// aligned to `align_of::<Self>()`, this returns `None`.
///
/// To also access the prefix bytes, use [`Ref::new_from_prefix`]. Then, use
/// [`Ref::into_ref`] to get a `&Self` with the same lifetime.
/// This method returns both a reference to the first `size_of::<Self>()`
/// bytes of `bytes` interpreted as `Self`, and a reference to the remaining
/// bytes. If `bytes.len() < size_of::<Self>()` or `bytes` is not aligned to
/// `align_of::<Self>()`, this returns `None`.
///
/// # Examples
///
Expand All @@ -2235,31 +2233,31 @@ pub unsafe trait FromBytes: FromZeros {
/// // These are more bytes than are needed to encode a `Packet`.
/// let bytes = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14][..];
///
/// let packet = Packet::ref_from_prefix(bytes).unwrap();
/// let (packet, excess) = Packet::ref_from_prefix(bytes).unwrap();
///
/// assert_eq!(packet.header.src_port, [0, 1]);
/// assert_eq!(packet.header.dst_port, [2, 3]);
/// assert_eq!(packet.header.length, [4, 5]);
/// assert_eq!(packet.header.checksum, [6, 7]);
/// assert_eq!(packet.body, [[8, 9], [10, 11], [12, 13]]);
/// assert_eq!(excess, &[14u8][..]);
/// ```
#[must_use = "has no side effects"]
#[inline]
fn ref_from_prefix(bytes: &[u8]) -> Option<&Self>
fn ref_from_prefix(bytes: &[u8]) -> Option<(&Self, &[u8])>
where
Self: KnownLayout + NoCell,
{
Ref::<&[u8], Self>::bikeshed_new_from_prefix_known_layout(bytes).map(|(r, _)| r.into_ref())
Ref::<&[u8], Self>::bikeshed_new_from_prefix_known_layout(bytes)
.map(|(r, s)| (r.into_ref(), s))
}

/// Interprets the suffix of the given `bytes` as a `&Self` without copying.
///
/// `ref_from_suffix` returns a reference to the last `size_of::<Self>()`
/// bytes of `bytes`. If `bytes.len() < size_of::<Self>()` or the suffix of
/// `bytes` is not aligned to `align_of::<Self>()`, this returns `None`.
///
/// To also access the suffix bytes, use [`Ref::new_from_suffix`]. Then, use
/// [`Ref::into_ref`] to get a `&Self` with the same lifetime.
/// This method returns both a reference to the last `size_of::<Self>()`
/// bytes of `bytes` interpreted as `Self`, and a reference to the preceding
/// bytes. If `bytes.len() < size_of::<Self>()` or the suffix of `bytes` is
/// not aligned to `align_of::<Self>()`, this returns `None`.
///
/// # Examples
///
Expand All @@ -2276,17 +2274,19 @@ pub unsafe trait FromBytes: FromZeros {
/// // These are more bytes than are needed to encode a `PacketTrailer`.
/// let bytes = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..];
///
/// let trailer = PacketTrailer::ref_from_suffix(bytes).unwrap();
/// let (prefix, trailer) = PacketTrailer::ref_from_suffix(bytes).unwrap();
///
/// assert_eq!(prefix, &[0, 1, 2, 3, 4, 5][..]);
/// assert_eq!(trailer.frame_check_sequence, [6, 7, 8, 9]);
/// ```
#[must_use = "has no side effects"]
#[inline]
fn ref_from_suffix(bytes: &[u8]) -> Option<&Self>
fn ref_from_suffix(bytes: &[u8]) -> Option<(&[u8], &Self)>
where
Self: NoCell + KnownLayout,
{
Ref::<&[u8], Self>::bikeshed_new_from_suffix_known_layout(bytes).map(|(_, r)| r.into_ref())
Ref::<&[u8], Self>::bikeshed_new_from_suffix_known_layout(bytes)
.map(|(p, r)| (p, r.into_ref()))
}

/// Interprets the given `bytes` as a `&mut Self` without copying.
Expand Down Expand Up @@ -2335,12 +2335,10 @@ pub unsafe trait FromBytes: FromZeros {
/// Interprets the prefix of the given `bytes` as a `&mut Self` without
/// copying.
///
/// `mut_from_prefix` returns a reference to the first `size_of::<Self>()`
/// bytes of `bytes`. If `bytes.len() < size_of::<Self>()` or `bytes` is not
/// aligned to `align_of::<Self>()`, this returns `None`.
///
/// To also access the prefix bytes, use [`Ref::new_from_prefix`]. Then, use
/// [`Ref::into_mut`] to get a `&mut Self` with the same lifetime.
/// This method returns both a reference to the first `size_of::<Self>()`
/// bytes of `bytes` interpreted as `Self`, and a reference to the remaining
/// bytes. If `bytes.len() < size_of::<Self>()` or `bytes` is not aligned to
/// `align_of::<Self>()`, this returns `None`.
///
/// # Examples
///
Expand All @@ -2360,35 +2358,36 @@ pub unsafe trait FromBytes: FromZeros {
/// // These are more bytes than are needed to encode a `PacketHeader`.
/// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..];
///
/// let header = PacketHeader::mut_from_prefix(bytes).unwrap();
/// let (header, body) = PacketHeader::mut_from_prefix(bytes).unwrap();
///
/// assert_eq!(header.src_port, [0, 1]);
/// assert_eq!(header.dst_port, [2, 3]);
/// assert_eq!(header.length, [4, 5]);
/// assert_eq!(header.checksum, [6, 7]);
/// assert_eq!(body, &[8, 9][..]);
///
/// header.checksum = [0, 0];
/// body.fill(1);
///
/// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 0, 0, 8, 9]);
/// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 0, 0, 1, 1]);
/// ```
#[must_use = "has no side effects"]
#[inline]
fn mut_from_prefix(bytes: &mut [u8]) -> Option<&mut Self>
fn mut_from_prefix(bytes: &mut [u8]) -> Option<(&mut Self, &mut [u8])>
where
Self: IntoBytes + KnownLayout + NoCell,
{
Ref::<&mut [u8], Self>::bikeshed_new_from_prefix_known_layout(bytes)
.map(|(r, _)| r.into_mut())
.map(|(r, s)| (r.into_mut(), s))
}

/// Interprets the suffix of the given `bytes` as a `&mut Self` without copying.
///
/// `mut_from_suffix` returns a reference to the last `size_of::<Self>()`
/// bytes of `bytes`. If `bytes.len() < size_of::<Self>()` or the suffix of
/// `bytes` is not aligned to `align_of::<Self>()`, this returns `None`.
/// Interprets the suffix of the given `bytes` as a `&mut Self` without
/// copying.
///
/// To also access the suffix bytes, use [`Ref::new_from_suffix`]. Then,
/// use [`Ref::into_mut`] to get a `&mut Self` with the same lifetime.
/// This method returns both a reference to the last `size_of::<Self>()`
/// bytes of `bytes` interpreted as `Self`, and a reference to the preceding
/// bytes. If `bytes.len() < size_of::<Self>()` or the suffix of `bytes` is
/// not aligned to `align_of::<Self>()`, this returns `None`.
///
/// # Examples
///
Expand All @@ -2405,34 +2404,35 @@ pub unsafe trait FromBytes: FromZeros {
/// // These are more bytes than are needed to encode a `PacketTrailer`.
/// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 9][..];
///
/// let trailer = PacketTrailer::mut_from_suffix(bytes).unwrap();
/// let (prefix, trailer) = PacketTrailer::mut_from_suffix(bytes).unwrap();
///
/// assert_eq!(prefix, &[0u8, 1, 2, 3, 4, 5][..]);
/// assert_eq!(trailer.frame_check_sequence, [6, 7, 8, 9]);
///
/// trailer.frame_check_sequence = [0, 0, 0, 0];
/// prefix.fill(0);
/// trailer.frame_check_sequence.fill(1);
///
/// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 0, 0, 0, 0]);
/// assert_eq!(bytes, [0, 0, 0, 0, 0, 0, 1, 1, 1, 1]);
/// ```
#[must_use = "has no side effects"]
#[inline]
fn mut_from_suffix(bytes: &mut [u8]) -> Option<&mut Self>
fn mut_from_suffix(bytes: &mut [u8]) -> Option<(&mut [u8], &mut Self)>
where
Self: IntoBytes + KnownLayout + NoCell,
{
Ref::<&mut [u8], Self>::bikeshed_new_from_suffix_known_layout(bytes)
.map(|(_, r)| r.into_mut())
.map(|(p, r)| (p, r.into_mut()))
}

/// Interprets the prefix of the given `bytes` as a `&[Self]` with length
/// equal to `count` without copying.
///
/// This method 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
/// `&[Self]`, 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`.
/// This method verifies that `bytes.len() >= size_of::<T>() * count` and
/// that `bytes` is aligned to `align_of::<T>()`. It reinterprets the first
/// `size_of::<T>() * count` bytes from `bytes` to construct a `&[Self]`,
/// 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
///
Expand Down Expand Up @@ -2478,13 +2478,12 @@ pub unsafe trait FromBytes: FromZeros {
/// Interprets the suffix of the given `bytes` as a `&[Self]` with length
/// equal to `count` without copying.
///
/// This method 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
/// `&[Self]`, 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`.
/// This method verifies that `bytes.len() >= size_of::<T>() * count` and
/// that `bytes` is aligned to `align_of::<T>()`. It reinterprets the last
/// `size_of::<T>() * count` bytes from `bytes` to construct a `&[Self]`,
/// 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
///
Expand Down Expand Up @@ -2579,16 +2578,15 @@ pub unsafe trait FromBytes: FromZeros {
Ref::<_, [Self]>::new(bytes).map(|r| r.into_mut())
}

/// Interprets the prefix of the given `bytes` as a `&mut [Self]` with length
/// equal to `count` without copying.
/// Interprets the prefix of the given `bytes` as a `&mut [Self]` with
/// length equal to `count` without copying.
///
/// This method 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
/// `&[Self]`, 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`.
/// This method verifies that `bytes.len() >= size_of::<T>() * count` and
/// that `bytes` is aligned to `align_of::<T>()`. It reinterprets the first
/// `size_of::<T>() * count` bytes from `bytes` to construct a `&[Self]`,
/// 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
///
Expand Down Expand Up @@ -2623,8 +2621,9 @@ pub unsafe trait FromBytes: FromZeros {
/// assert_eq!(rest, &[8, 9]);
///
/// pixels[1] = Pixel { r: 0, g: 0, b: 0, a: 0 };
/// rest.fill(1);
///
/// assert_eq!(bytes, [0, 1, 2, 3, 0, 0, 0, 0, 8, 9]);
/// assert_eq!(bytes, [0, 1, 2, 3, 0, 0, 0, 0, 1, 1]);
/// ```
#[must_use = "has no side effects"]
#[inline]
Expand All @@ -2638,13 +2637,12 @@ pub unsafe trait FromBytes: FromZeros {
/// Interprets the suffix of the given `bytes` as a `&mut [Self]` with length
/// equal to `count` without copying.
///
/// This method 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
/// `&[Self]`, 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`.
/// This method verifies that `bytes.len() >= size_of::<T>() * count` and
/// that `bytes` is aligned to `align_of::<T>()`. It reinterprets the last
/// `size_of::<T>() * count` bytes from `bytes` to construct a `&[Self]`,
/// 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
///
Expand Down Expand Up @@ -2678,9 +2676,10 @@ pub unsafe trait FromBytes: FromZeros {
/// Pixel { r: 6, g: 7, b: 8, a: 9 },
/// ]);
///
/// rest.fill(9);
/// pixels[1] = Pixel { r: 0, g: 0, b: 0, a: 0 };
///
/// assert_eq!(bytes, [0, 1, 2, 3, 4, 5, 0, 0, 0, 0]);
/// assert_eq!(bytes, [9, 9, 2, 3, 4, 5, 0, 0, 0, 0]);
/// ```
#[must_use = "has no side effects"]
#[inline]
Expand Down Expand Up @@ -7846,12 +7845,21 @@ mod tests {
suffix.0 = 0x0101010101010101;
// The `[u8:9]` is a non-half size of the full buffer, which would catch
// `from_prefix` having the same implementation as `from_suffix` (issues #506, #511).
assert_eq!(<[u8; 9]>::ref_from_suffix(&buf.t[..]).unwrap(), &[7u8, 1, 1, 1, 1, 1, 1, 1, 1]);
let suffix = AU64::mut_from_suffix(&mut buf.t[1..]).unwrap();
assert_eq!(
<[u8; 9]>::ref_from_suffix(&buf.t[..]).unwrap(),
(&[0, 1, 2, 3, 4, 5, 6][..], &[7u8, 1, 1, 1, 1, 1, 1, 1, 1])
);
let (prefix, suffix) = AU64::mut_from_suffix(&mut buf.t[1..]).unwrap();
assert_eq!(prefix, &mut [1u8, 2, 3, 4, 5, 6, 7][..]);
suffix.0 = 0x0202020202020202;
<[u8; 10]>::mut_from_suffix(&mut buf.t[..]).unwrap()[0] = 42;
assert_eq!(<[u8; 9]>::ref_from_prefix(&buf.t[..]).unwrap(), &[0, 1, 2, 3, 4, 5, 42, 7, 2]);
<[u8; 2]>::mut_from_prefix(&mut buf.t[..]).unwrap()[1] = 30;
let (prefix, suffix) = <[u8; 10]>::mut_from_suffix(&mut buf.t[..]).unwrap();
assert_eq!(prefix, &mut [0u8, 1, 2, 3, 4, 5][..]);
suffix[0] = 42;
assert_eq!(
<[u8; 9]>::ref_from_prefix(&buf.t[..]).unwrap(),
(&[0u8, 1, 2, 3, 4, 5, 42, 7, 2], &[2u8, 2, 2, 2, 2, 2, 2][..])
);
<[u8; 2]>::mut_from_prefix(&mut buf.t[..]).unwrap().0[1] = 30;
assert_eq!(buf.t, [0, 30, 2, 3, 4, 5, 42, 7, 2, 2, 2, 2, 2, 2, 2, 2]);
}

Expand Down