Skip to content

Commit

Permalink
Add TryFromBytes::try_{ref,mut}_from_{bytes,prefix,suffix}_with_elems
Browse files Browse the repository at this point in the history
Makes progress on #5
  • Loading branch information
joshlf authored and jswrenn committed Sep 24, 2024
1 parent fbb0f8b commit b0d1b2f
Showing 1 changed file with 354 additions and 0 deletions.
354 changes: 354 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2011,6 +2011,360 @@ pub unsafe trait TryFromBytes {
}
}

/// Attempts to interpret the prefix of the given `source` as a `&Self` with
/// a DST length equal to `count`.
///
/// This method attempts to return a reference to the prefix of `source`
/// interpreted as a `Self` with `count` trailing elements, and a reference
/// to the remaining bytes. If the length of `source` is less than the size
/// of `Self` with `count` elements, if `source` is not appropriately
/// aligned, or if the prefix of `source` does not contain a valid instance
/// of `Self`, this returns `Err`. If [`Self: Unaligned`][self-unaligned],
/// you can [infallibly discard the alignment error][ConvertError::from].
///
/// [self-unaligned]: Unaligned
/// [slice-dst]: KnownLayout#dynamically-sized-types
///
/// # Examples
///
/// ```
/// # #![allow(non_camel_case_types)] // For C0::xC0
/// use zerocopy::TryFromBytes;
/// # use zerocopy_derive::*;
///
/// // The only valid value of this type is the byte `0xC0`
/// #[derive(TryFromBytes, KnownLayout, Immutable)]
/// #[repr(u8)]
/// enum C0 { xC0 = 0xC0 }
///
/// // The only valid value of this type is the bytes `0xC0C0`.
/// #[derive(TryFromBytes, KnownLayout, Immutable)]
/// #[repr(C)]
/// struct C0C0(C0, C0);
///
/// #[derive(TryFromBytes, KnownLayout, Immutable)]
/// #[repr(C)]
/// struct Packet {
/// magic_number: C0C0,
/// mug_size: u8,
/// temperature: u8,
/// marshmallows: [[u8; 2]],
/// }
///
/// let bytes = &[0xC0, 0xC0, 240, 77, 2, 3, 4, 5, 6, 7, 8][..];
///
/// let (packet, suffix) = Packet::try_ref_from_prefix_with_elems(bytes, 3).unwrap();
///
/// assert_eq!(packet.mug_size, 240);
/// assert_eq!(packet.temperature, 77);
/// assert_eq!(packet.marshmallows, [[2, 3], [4, 5], [6, 7]]);
/// assert_eq!(suffix, &[8u8][..]);
///
/// // These bytes are not valid instance of `Packet`.
/// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 77, 240, 0xC0, 0xC0][..];
/// assert!(Packet::try_ref_from_prefix_with_elems(bytes, 3).is_err());
/// ```
///
/// Since an explicit `count` is provided, this method supports types with
/// zero-sized trailing slice elements. Methods such as [`try_ref_from_prefix`]
/// which do not take an explicit count do not support such types.
///
/// ```
/// use core::num::NonZeroU16;
/// use zerocopy::*;
/// # use zerocopy_derive::*;
///
/// #[derive(TryFromBytes, Immutable, KnownLayout)]
/// #[repr(C)]
/// struct ZSTy {
/// leading_sized: NonZeroU16,
/// trailing_dst: [()],
/// }
///
/// let src = &[85, 85][..];
/// let (zsty, _) = ZSTy::try_ref_from_prefix_with_elems(src, 42).unwrap();
/// assert_eq!(zsty.trailing_dst.len(), 42);
/// ```
///
/// [`try_ref_from_prefix`]: TryFromBytes::try_ref_from_prefix
#[must_use = "has no side effects"]
#[inline]
fn try_ref_from_prefix_with_elems(
source: &[u8],
count: usize,
) -> Result<(&Self, &[u8]), TryCastError<&[u8], Self>>
where
Self: KnownLayout<PointerMetadata = usize> + Immutable,
{
try_ref_from_prefix_suffix(source, CastType::Prefix, Some(count))
}

/// Attempts to interpret the suffix of the given `source` as a `&Self` with
/// a DST length equal to `count`.
///
/// This method attempts to return a reference to the suffix of `source`
/// interpreted as a `Self` with `count` trailing elements, and a reference
/// to the preceding bytes. If the length of `source` is less than the size
/// of `Self` with `count` elements, if the suffix of `source` is not
/// appropriately aligned, or if the suffix of `source` does not contain a
/// valid instance of `Self`, this returns `Err`. If [`Self:
/// Unaligned`][self-unaligned], you can [infallibly discard the alignment
/// error][ConvertError::from].
///
/// [self-unaligned]: Unaligned
/// [slice-dst]: KnownLayout#dynamically-sized-types
///
/// # Examples
///
/// ```
/// # #![allow(non_camel_case_types)] // For C0::xC0
/// use zerocopy::TryFromBytes;
/// # use zerocopy_derive::*;
///
/// // The only valid value of this type is the byte `0xC0`
/// #[derive(TryFromBytes, KnownLayout, Immutable)]
/// #[repr(u8)]
/// enum C0 { xC0 = 0xC0 }
///
/// // The only valid value of this type is the bytes `0xC0C0`.
/// #[derive(TryFromBytes, KnownLayout, Immutable)]
/// #[repr(C)]
/// struct C0C0(C0, C0);
///
/// #[derive(TryFromBytes, KnownLayout, Immutable)]
/// #[repr(C)]
/// struct Packet {
/// magic_number: C0C0,
/// mug_size: u8,
/// temperature: u8,
/// marshmallows: [[u8; 2]],
/// }
///
/// let bytes = &[123, 0xC0, 0xC0, 240, 77, 2, 3, 4, 5, 6, 7][..];
///
/// let (prefix, packet) = Packet::try_ref_from_suffix_with_elems(bytes, 3).unwrap();
///
/// assert_eq!(packet.mug_size, 240);
/// assert_eq!(packet.temperature, 77);
/// assert_eq!(packet.marshmallows, [[2, 3], [4, 5], [6, 7]]);
/// assert_eq!(prefix, &[123u8][..]);
///
/// // These bytes are not valid instance of `Packet`.
/// let bytes = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 77, 240, 0xC0, 0xC0][..];
/// assert!(Packet::try_ref_from_suffix_with_elems(bytes, 3).is_err());
/// ```
///
/// Since an explicit `count` is provided, this method supports types with
/// zero-sized trailing slice elements. Methods such as [`try_ref_from_prefix`]
/// which do not take an explicit count do not support such types.
///
/// ```
/// use core::num::NonZeroU16;
/// use zerocopy::*;
/// # use zerocopy_derive::*;
///
/// #[derive(TryFromBytes, Immutable, KnownLayout)]
/// #[repr(C)]
/// struct ZSTy {
/// leading_sized: NonZeroU16,
/// trailing_dst: [()],
/// }
///
/// let src = &[85, 85][..];
/// let (_, zsty) = ZSTy::try_ref_from_suffix_with_elems(src, 42).unwrap();
/// assert_eq!(zsty.trailing_dst.len(), 42);
/// ```
///
/// [`try_ref_from_prefix`]: TryFromBytes::try_ref_from_prefix
#[must_use = "has no side effects"]
#[inline]
fn try_ref_from_suffix_with_elems(
source: &[u8],
count: usize,
) -> Result<(&[u8], &Self), TryCastError<&[u8], Self>>
where
Self: KnownLayout<PointerMetadata = usize> + Immutable,
{
try_ref_from_prefix_suffix(source, CastType::Suffix, Some(count)).map(swap)
}

/// Attempts to interpret the prefix of the given `source` as a `&mut Self`
/// with a DST length equal to `count`.
///
/// This method attempts to return a reference to the prefix of `source`
/// interpreted as a `Self` with `count` trailing elements, and a reference
/// to the remaining bytes. If the length of `source` is less than the size
/// of `Self` with `count` elements, if `source` is not appropriately
/// aligned, or if the prefix of `source` does not contain a valid instance
/// of `Self`, this returns `Err`. If [`Self: Unaligned`][self-unaligned],
/// you can [infallibly discard the alignment error][ConvertError::from].
///
/// [self-unaligned]: Unaligned
/// [slice-dst]: KnownLayout#dynamically-sized-types
///
/// # Examples
///
/// ```
/// # #![allow(non_camel_case_types)] // For C0::xC0
/// use zerocopy::TryFromBytes;
/// # use zerocopy_derive::*;
///
/// // The only valid value of this type is the byte `0xC0`
/// #[derive(TryFromBytes, KnownLayout, Immutable)]
/// #[repr(u8)]
/// enum C0 { xC0 = 0xC0 }
///
/// // The only valid value of this type is the bytes `0xC0C0`.
/// #[derive(TryFromBytes, KnownLayout, Immutable)]
/// #[repr(C)]
/// struct C0C0(C0, C0);
///
/// #[derive(TryFromBytes, KnownLayout, Immutable)]
/// #[repr(C)]
/// struct Packet {
/// magic_number: C0C0,
/// mug_size: u8,
/// temperature: u8,
/// marshmallows: [[u8; 2]],
/// }
///
/// let bytes = &mut [0xC0, 0xC0, 240, 77, 2, 3, 4, 5, 6, 7, 8][..];
///
/// let (packet, suffix) = Packet::try_mut_from_prefix_with_elems(bytes, 3).unwrap();
///
/// assert_eq!(packet.mug_size, 240);
/// assert_eq!(packet.temperature, 77);
/// assert_eq!(packet.marshmallows, [[2, 3], [4, 5], [6, 7]]);
/// assert_eq!(suffix, &[8u8][..]);
///
/// // These bytes are not valid instance of `Packet`.
/// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 77, 240, 0xC0, 0xC0][..];
/// assert!(Packet::try_mut_from_prefix_with_elems(bytes, 3).is_err());
/// ```
///
/// Since an explicit `count` is provided, this method supports types with
/// zero-sized trailing slice elements. Methods such as [`try_mut_from_prefix`]
/// which do not take an explicit count do not support such types.
///
/// ```
/// use core::num::NonZeroU16;
/// use zerocopy::*;
/// # use zerocopy_derive::*;
///
/// #[derive(TryFromBytes, Immutable, KnownLayout)]
/// #[repr(C)]
/// struct ZSTy {
/// leading_sized: NonZeroU16,
/// trailing_dst: [()],
/// }
///
/// let src = &mut [85, 85][..];
/// let (zsty, _) = ZSTy::try_mut_from_prefix_with_elems(src, 42).unwrap();
/// assert_eq!(zsty.trailing_dst.len(), 42);
/// ```
///
/// [`try_mut_from_prefix`]: TryFromBytes::try_mut_from_prefix
#[must_use = "has no side effects"]
#[inline]
fn try_mut_from_prefix_with_elems(
source: &mut [u8],
count: usize,
) -> Result<(&mut Self, &mut [u8]), TryCastError<&mut [u8], Self>>
where
Self: KnownLayout<PointerMetadata = usize> + Immutable,
{
try_mut_from_prefix_suffix(source, CastType::Prefix, Some(count))
}

/// Attempts to interpret the suffix of the given `source` as a `&mut Self`
/// with a DST length equal to `count`.
///
/// This method attempts to return a reference to the suffix of `source`
/// interpreted as a `Self` with `count` trailing elements, and a reference
/// to the preceding bytes. If the length of `source` is less than the size
/// of `Self` with `count` elements, if the suffix of `source` is not
/// appropriately aligned, or if the suffix of `source` does not contain a
/// valid instance of `Self`, this returns `Err`. If [`Self:
/// Unaligned`][self-unaligned], you can [infallibly discard the alignment
/// error][ConvertError::from].
///
/// [self-unaligned]: Unaligned
/// [slice-dst]: KnownLayout#dynamically-sized-types
///
/// # Examples
///
/// ```
/// # #![allow(non_camel_case_types)] // For C0::xC0
/// use zerocopy::TryFromBytes;
/// # use zerocopy_derive::*;
///
/// // The only valid value of this type is the byte `0xC0`
/// #[derive(TryFromBytes, KnownLayout, Immutable)]
/// #[repr(u8)]
/// enum C0 { xC0 = 0xC0 }
///
/// // The only valid value of this type is the bytes `0xC0C0`.
/// #[derive(TryFromBytes, KnownLayout, Immutable)]
/// #[repr(C)]
/// struct C0C0(C0, C0);
///
/// #[derive(TryFromBytes, KnownLayout, Immutable)]
/// #[repr(C)]
/// struct Packet {
/// magic_number: C0C0,
/// mug_size: u8,
/// temperature: u8,
/// marshmallows: [[u8; 2]],
/// }
///
/// let bytes = &mut [123, 0xC0, 0xC0, 240, 77, 2, 3, 4, 5, 6, 7][..];
///
/// let (prefix, packet) = Packet::try_mut_from_suffix_with_elems(bytes, 3).unwrap();
///
/// assert_eq!(packet.mug_size, 240);
/// assert_eq!(packet.temperature, 77);
/// assert_eq!(packet.marshmallows, [[2, 3], [4, 5], [6, 7]]);
/// assert_eq!(prefix, &[123u8][..]);
///
/// // These bytes are not valid instance of `Packet`.
/// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 77, 240, 0xC0, 0xC0][..];
/// assert!(Packet::try_mut_from_suffix_with_elems(bytes, 3).is_err());
/// ```
///
/// Since an explicit `count` is provided, this method supports types with
/// zero-sized trailing slice elements. Methods such as [`try_mut_from_prefix`]
/// which do not take an explicit count do not support such types.
///
/// ```
/// use core::num::NonZeroU16;
/// use zerocopy::*;
/// # use zerocopy_derive::*;
///
/// #[derive(TryFromBytes, Immutable, KnownLayout)]
/// #[repr(C)]
/// struct ZSTy {
/// leading_sized: NonZeroU16,
/// trailing_dst: [()],
/// }
///
/// let src = &mut [85, 85][..];
/// let (_, zsty) = ZSTy::try_mut_from_suffix_with_elems(src, 42).unwrap();
/// assert_eq!(zsty.trailing_dst.len(), 42);
/// ```
///
/// [`try_mut_from_prefix`]: TryFromBytes::try_mut_from_prefix
#[must_use = "has no side effects"]
#[inline]
fn try_mut_from_suffix_with_elems(
source: &mut [u8],
count: usize,
) -> Result<(&mut [u8], &mut Self), TryCastError<&mut [u8], Self>>
where
Self: KnownLayout<PointerMetadata = usize> + Immutable,
{
try_mut_from_prefix_suffix(source, CastType::Suffix, Some(count)).map(swap)
}

/// Attempts to read the given `source` as a `Self`.
///
/// If `source.len() != size_of::<Self>()` or the bytes are not a valid
Expand Down

0 comments on commit b0d1b2f

Please sign in to comment.