Skip to content

Commit 5cdb8d8

Browse files
joshlfjswrenn
authored andcommitted
Add TryFromBytes::try_{ref,mut}_from_{bytes,prefix,suffix}_with_elems
Makes progress on #5
1 parent fbb0f8b commit 5cdb8d8

File tree

1 file changed

+354
-0
lines changed

1 file changed

+354
-0
lines changed

src/lib.rs

Lines changed: 354 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2011,6 +2011,360 @@ pub unsafe trait TryFromBytes {
20112011
}
20122012
}
20132013

2014+
/// Attempts to interpret the prefix of the given `source` as a `&Self` with
2015+
/// a DST length equal to `count`.
2016+
///
2017+
/// This method attempts to return a reference to the prefix of `source`
2018+
/// interpreted as a `Self` with `count` trailing elements, and a reference
2019+
/// to the remaining bytes. If the length of `source` is less than the size
2020+
/// of `Self` with `count` elements, if `source` is not appropriately
2021+
/// aligned, or if the prefix of `source` does not contain a valid instance
2022+
/// of `Self`, this returns `Err`. If [`Self: Unaligned`][self-unaligned],
2023+
/// you can [infallibly discard the alignment error][ConvertError::from].
2024+
///
2025+
/// [self-unaligned]: Unaligned
2026+
/// [slice-dst]: KnownLayout#dynamically-sized-types
2027+
///
2028+
/// # Examples
2029+
///
2030+
/// ```
2031+
/// # #![allow(non_camel_case_types)] // For C0::xC0
2032+
/// use zerocopy::TryFromBytes;
2033+
/// # use zerocopy_derive::*;
2034+
///
2035+
/// // The only valid value of this type is the byte `0xC0`
2036+
/// #[derive(TryFromBytes, KnownLayout, Immutable)]
2037+
/// #[repr(u8)]
2038+
/// enum C0 { xC0 = 0xC0 }
2039+
///
2040+
/// // The only valid value of this type is the bytes `0xC0C0`.
2041+
/// #[derive(TryFromBytes, KnownLayout, Immutable)]
2042+
/// #[repr(C)]
2043+
/// struct C0C0(C0, C0);
2044+
///
2045+
/// #[derive(TryFromBytes, KnownLayout, Immutable)]
2046+
/// #[repr(C)]
2047+
/// struct Packet {
2048+
/// magic_number: C0C0,
2049+
/// mug_size: u8,
2050+
/// temperature: u8,
2051+
/// marshmallows: [[u8; 2]],
2052+
/// }
2053+
///
2054+
/// let bytes = &[0xC0, 0xC0, 240, 77, 2, 3, 4, 5, 6, 7, 8][..];
2055+
///
2056+
/// let (packet, suffix) = Packet::try_ref_from_prefix_with_elems(bytes, 3).unwrap();
2057+
///
2058+
/// assert_eq!(packet.mug_size, 240);
2059+
/// assert_eq!(packet.temperature, 77);
2060+
/// assert_eq!(packet.marshmallows, [[2, 3], [4, 5], [6, 7]]);
2061+
/// assert_eq!(suffix, &[8u8][..]);
2062+
///
2063+
/// // These bytes are not valid instance of `Packet`.
2064+
/// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 77, 240, 0xC0, 0xC0][..];
2065+
/// assert!(Packet::try_ref_from_prefix_with_elems(bytes, 3).is_err());
2066+
/// ```
2067+
///
2068+
/// Since an explicit `count` is provided, this method supports types with
2069+
/// zero-sized trailing slice elements. Methods such as [`try_ref_from_prefix`]
2070+
/// which do not take an explicit count do not support such types.
2071+
///
2072+
/// ```
2073+
/// use core::num::NonZeroU16;
2074+
/// use zerocopy::*;
2075+
/// # use zerocopy_derive::*;
2076+
///
2077+
/// #[derive(TryFromBytes, Immutable, KnownLayout)]
2078+
/// #[repr(C)]
2079+
/// struct ZSTy {
2080+
/// leading_sized: NonZeroU16,
2081+
/// trailing_dst: [()],
2082+
/// }
2083+
///
2084+
/// let src = &[85, 85][..];
2085+
/// let (zsty, _) = ZSTy::try_ref_from_prefix_with_elems(src, 42).unwrap();
2086+
/// assert_eq!(zsty.trailing_dst.len(), 42);
2087+
/// ```
2088+
///
2089+
/// [`try_ref_from_prefix`]: TryFromBytes::try_ref_from_prefix
2090+
#[must_use = "has no side effects"]
2091+
#[inline]
2092+
fn try_ref_from_prefix_with_elems(
2093+
source: &[u8],
2094+
count: usize,
2095+
) -> Result<(&Self, &[u8]), TryCastError<&[u8], Self>>
2096+
where
2097+
Self: KnownLayout<PointerMetadata = usize> + Immutable,
2098+
{
2099+
try_ref_from_prefix_suffix(source, CastType::Prefix, Some(count))
2100+
}
2101+
2102+
/// Attempts to interpret the suffix of the given `source` as a `&Self` with
2103+
/// a DST length equal to `count`.
2104+
///
2105+
/// This method attempts to return a reference to the suffix of `source`
2106+
/// interpreted as a `Self` with `count` trailing elements, and a reference
2107+
/// to the preceding bytes. If the length of `source` is less than the size
2108+
/// of `Self` with `count` elements, if the suffix of `source` is not
2109+
/// appropriately aligned, or if the suffix of `source` does not contain a
2110+
/// valid instance of `Self`, this returns `Err`. If [`Self:
2111+
/// Unaligned`][self-unaligned], you can [infallibly discard the alignment
2112+
/// error][ConvertError::from].
2113+
///
2114+
/// [self-unaligned]: Unaligned
2115+
/// [slice-dst]: KnownLayout#dynamically-sized-types
2116+
///
2117+
/// # Examples
2118+
///
2119+
/// ```
2120+
/// # #![allow(non_camel_case_types)] // For C0::xC0
2121+
/// use zerocopy::TryFromBytes;
2122+
/// # use zerocopy_derive::*;
2123+
///
2124+
/// // The only valid value of this type is the byte `0xC0`
2125+
/// #[derive(TryFromBytes, KnownLayout, Immutable)]
2126+
/// #[repr(u8)]
2127+
/// enum C0 { xC0 = 0xC0 }
2128+
///
2129+
/// // The only valid value of this type is the bytes `0xC0C0`.
2130+
/// #[derive(TryFromBytes, KnownLayout, Immutable)]
2131+
/// #[repr(C)]
2132+
/// struct C0C0(C0, C0);
2133+
///
2134+
/// #[derive(TryFromBytes, KnownLayout, Immutable)]
2135+
/// #[repr(C)]
2136+
/// struct Packet {
2137+
/// magic_number: C0C0,
2138+
/// mug_size: u8,
2139+
/// temperature: u8,
2140+
/// marshmallows: [[u8; 2]],
2141+
/// }
2142+
///
2143+
/// let bytes = &[123, 0xC0, 0xC0, 240, 77, 2, 3, 4, 5, 6, 7][..];
2144+
///
2145+
/// let (prefix, packet) = Packet::try_ref_from_suffix_with_elems(bytes, 3).unwrap();
2146+
///
2147+
/// assert_eq!(packet.mug_size, 240);
2148+
/// assert_eq!(packet.temperature, 77);
2149+
/// assert_eq!(packet.marshmallows, [[2, 3], [4, 5], [6, 7]]);
2150+
/// assert_eq!(prefix, &[123u8][..]);
2151+
///
2152+
/// // These bytes are not valid instance of `Packet`.
2153+
/// let bytes = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 77, 240, 0xC0, 0xC0][..];
2154+
/// assert!(Packet::try_ref_from_suffix_with_elems(bytes, 3).is_err());
2155+
/// ```
2156+
///
2157+
/// Since an explicit `count` is provided, this method supports types with
2158+
/// zero-sized trailing slice elements. Methods such as [`try_ref_from_prefix`]
2159+
/// which do not take an explicit count do not support such types.
2160+
///
2161+
/// ```
2162+
/// use core::num::NonZeroU16;
2163+
/// use zerocopy::*;
2164+
/// # use zerocopy_derive::*;
2165+
///
2166+
/// #[derive(TryFromBytes, Immutable, KnownLayout)]
2167+
/// #[repr(C)]
2168+
/// struct ZSTy {
2169+
/// leading_sized: NonZeroU16,
2170+
/// trailing_dst: [()],
2171+
/// }
2172+
///
2173+
/// let src = &[85, 85][..];
2174+
/// let (_, zsty) = ZSTy::try_ref_from_suffix_with_elems(src, 42).unwrap();
2175+
/// assert_eq!(zsty.trailing_dst.len(), 42);
2176+
/// ```
2177+
///
2178+
/// [`try_ref_from_prefix`]: TryFromBytes::try_ref_from_prefix
2179+
#[must_use = "has no side effects"]
2180+
#[inline]
2181+
fn try_ref_from_suffix_with_elems(
2182+
source: &[u8],
2183+
count: usize,
2184+
) -> Result<(&[u8], &Self), TryCastError<&[u8], Self>>
2185+
where
2186+
Self: KnownLayout<PointerMetadata = usize> + Immutable,
2187+
{
2188+
try_ref_from_prefix_suffix(source, CastType::Suffix, Some(count)).map(swap)
2189+
}
2190+
2191+
/// Attempts to interpret the prefix of the given `source` as a `&Self` with
2192+
/// a DST length equal to `count`.
2193+
///
2194+
/// This method attempts to return a reference to the prefix of `source`
2195+
/// interpreted as a `Self` with `count` trailing elements, and a reference
2196+
/// to the remaining bytes. If the length of `source` is less than the size
2197+
/// of `Self` with `count` elements, if `source` is not appropriately
2198+
/// aligned, or if the prefix of `source` does not contain a valid instance
2199+
/// of `Self`, this returns `Err`. If [`Self: Unaligned`][self-unaligned],
2200+
/// you can [infallibly discard the alignment error][ConvertError::from].
2201+
///
2202+
/// [self-unaligned]: Unaligned
2203+
/// [slice-dst]: KnownLayout#dynamically-sized-types
2204+
///
2205+
/// # Examples
2206+
///
2207+
/// ```
2208+
/// # #![allow(non_camel_case_types)] // For C0::xC0
2209+
/// use zerocopy::TryFromBytes;
2210+
/// # use zerocopy_derive::*;
2211+
///
2212+
/// // The only valid value of this type is the byte `0xC0`
2213+
/// #[derive(TryFromBytes, KnownLayout, Immutable)]
2214+
/// #[repr(u8)]
2215+
/// enum C0 { xC0 = 0xC0 }
2216+
///
2217+
/// // The only valid value of this type is the bytes `0xC0C0`.
2218+
/// #[derive(TryFromBytes, KnownLayout, Immutable)]
2219+
/// #[repr(C)]
2220+
/// struct C0C0(C0, C0);
2221+
///
2222+
/// #[derive(TryFromBytes, KnownLayout, Immutable)]
2223+
/// #[repr(C)]
2224+
/// struct Packet {
2225+
/// magic_number: C0C0,
2226+
/// mug_size: u8,
2227+
/// temperature: u8,
2228+
/// marshmallows: [[u8; 2]],
2229+
/// }
2230+
///
2231+
/// let bytes = &mut [0xC0, 0xC0, 240, 77, 2, 3, 4, 5, 6, 7, 8][..];
2232+
///
2233+
/// let (packet, suffix) = Packet::try_mut_from_prefix_with_elems(bytes, 3).unwrap();
2234+
///
2235+
/// assert_eq!(packet.mug_size, 240);
2236+
/// assert_eq!(packet.temperature, 77);
2237+
/// assert_eq!(packet.marshmallows, [[2, 3], [4, 5], [6, 7]]);
2238+
/// assert_eq!(suffix, &[8u8][..]);
2239+
///
2240+
/// // These bytes are not valid instance of `Packet`.
2241+
/// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 77, 240, 0xC0, 0xC0][..];
2242+
/// assert!(Packet::try_mut_from_prefix_with_elems(bytes, 3).is_err());
2243+
/// ```
2244+
///
2245+
/// Since an explicit `count` is provided, this method supports types with
2246+
/// zero-sized trailing slice elements. Methods such as [`try_mut_from_prefix`]
2247+
/// which do not take an explicit count do not support such types.
2248+
///
2249+
/// ```
2250+
/// use core::num::NonZeroU16;
2251+
/// use zerocopy::*;
2252+
/// # use zerocopy_derive::*;
2253+
///
2254+
/// #[derive(TryFromBytes, Immutable, KnownLayout)]
2255+
/// #[repr(C)]
2256+
/// struct ZSTy {
2257+
/// leading_sized: NonZeroU16,
2258+
/// trailing_dst: [()],
2259+
/// }
2260+
///
2261+
/// let src = &mut [85, 85][..];
2262+
/// let (zsty, _) = ZSTy::try_mut_from_prefix_with_elems(src, 42).unwrap();
2263+
/// assert_eq!(zsty.trailing_dst.len(), 42);
2264+
/// ```
2265+
///
2266+
/// [`try_mut_from_prefix`]: TryFromBytes::try_mut_from_prefix
2267+
#[must_use = "has no side effects"]
2268+
#[inline]
2269+
fn try_mut_from_prefix_with_elems(
2270+
source: &mut [u8],
2271+
count: usize,
2272+
) -> Result<(&mut Self, &mut [u8]), TryCastError<&mut [u8], Self>>
2273+
where
2274+
Self: KnownLayout<PointerMetadata = usize> + Immutable,
2275+
{
2276+
try_mut_from_prefix_suffix(source, CastType::Prefix, Some(count))
2277+
}
2278+
2279+
/// Attempts to interpret the suffix of the given `source` as a `&mut Self`
2280+
/// with a DST length equal to `count`.
2281+
///
2282+
/// This method attempts to return a reference to the suffix of `source`
2283+
/// interpreted as a `Self` with `count` trailing elements, and a reference
2284+
/// to the preceding bytes. If the length of `source` is less than the size
2285+
/// of `Self` with `count` elements, if the suffix of `source` is not
2286+
/// appropriately aligned, or if the suffix of `source` does not contain a
2287+
/// valid instance of `Self`, this returns `Err`. If [`Self:
2288+
/// Unaligned`][self-unaligned], you can [infallibly discard the alignment
2289+
/// error][ConvertError::from].
2290+
///
2291+
/// [self-unaligned]: Unaligned
2292+
/// [slice-dst]: KnownLayout#dynamically-sized-types
2293+
///
2294+
/// # Examples
2295+
///
2296+
/// ```
2297+
/// # #![allow(non_camel_case_types)] // For C0::xC0
2298+
/// use zerocopy::TryFromBytes;
2299+
/// # use zerocopy_derive::*;
2300+
///
2301+
/// // The only valid value of this type is the byte `0xC0`
2302+
/// #[derive(TryFromBytes, KnownLayout, Immutable)]
2303+
/// #[repr(u8)]
2304+
/// enum C0 { xC0 = 0xC0 }
2305+
///
2306+
/// // The only valid value of this type is the bytes `0xC0C0`.
2307+
/// #[derive(TryFromBytes, KnownLayout, Immutable)]
2308+
/// #[repr(C)]
2309+
/// struct C0C0(C0, C0);
2310+
///
2311+
/// #[derive(TryFromBytes, KnownLayout, Immutable)]
2312+
/// #[repr(C)]
2313+
/// struct Packet {
2314+
/// magic_number: C0C0,
2315+
/// mug_size: u8,
2316+
/// temperature: u8,
2317+
/// marshmallows: [[u8; 2]],
2318+
/// }
2319+
///
2320+
/// let bytes = &mut [123, 0xC0, 0xC0, 240, 77, 2, 3, 4, 5, 6, 7][..];
2321+
///
2322+
/// let (prefix, packet) = Packet::try_mut_from_suffix_with_elems(bytes, 3).unwrap();
2323+
///
2324+
/// assert_eq!(packet.mug_size, 240);
2325+
/// assert_eq!(packet.temperature, 77);
2326+
/// assert_eq!(packet.marshmallows, [[2, 3], [4, 5], [6, 7]]);
2327+
/// assert_eq!(prefix, &[123u8][..]);
2328+
///
2329+
/// // These bytes are not valid instance of `Packet`.
2330+
/// let bytes = &mut [0, 1, 2, 3, 4, 5, 6, 7, 8, 77, 240, 0xC0, 0xC0][..];
2331+
/// assert!(Packet::try_mut_from_suffix_with_elems(bytes, 3).is_err());
2332+
/// ```
2333+
///
2334+
/// Since an explicit `count` is provided, this method supports types with
2335+
/// zero-sized trailing slice elements. Methods such as [`try_mut_from_prefix`]
2336+
/// which do not take an explicit count do not support such types.
2337+
///
2338+
/// ```
2339+
/// use core::num::NonZeroU16;
2340+
/// use zerocopy::*;
2341+
/// # use zerocopy_derive::*;
2342+
///
2343+
/// #[derive(TryFromBytes, Immutable, KnownLayout)]
2344+
/// #[repr(C)]
2345+
/// struct ZSTy {
2346+
/// leading_sized: NonZeroU16,
2347+
/// trailing_dst: [()],
2348+
/// }
2349+
///
2350+
/// let src = &mut [85, 85][..];
2351+
/// let (_, zsty) = ZSTy::try_mut_from_suffix_with_elems(src, 42).unwrap();
2352+
/// assert_eq!(zsty.trailing_dst.len(), 42);
2353+
/// ```
2354+
///
2355+
/// [`try_mut_from_prefix`]: TryFromBytes::try_mut_from_prefix
2356+
#[must_use = "has no side effects"]
2357+
#[inline]
2358+
fn try_mut_from_suffix_with_elems(
2359+
source: &mut [u8],
2360+
count: usize,
2361+
) -> Result<(&mut [u8], &mut Self), TryCastError<&mut [u8], Self>>
2362+
where
2363+
Self: KnownLayout<PointerMetadata = usize> + Immutable,
2364+
{
2365+
try_mut_from_prefix_suffix(source, CastType::Suffix, Some(count)).map(swap)
2366+
}
2367+
20142368
/// Attempts to read the given `source` as a `Self`.
20152369
///
20162370
/// If `source.len() != size_of::<Self>()` or the bytes are not a valid

0 commit comments

Comments
 (0)