#[inline]
pub(crate) fn bytes(data: &[u8], offset: usize, len: usize) -> Option<&[u8]> {
data.get(offset..offset.checked_add(len)?)
}
#[inline]
pub(crate) fn array<const N: usize>(data: &[u8], offset: usize) -> Option<[u8; N]> {
bytes(data, offset, N)?.try_into().ok()
}
#[inline]
pub(crate) fn u16_le(data: &[u8], offset: usize) -> Option<u16> {
array(data, offset).map(u16::from_le_bytes)
}
#[inline]
pub(crate) fn u16_be(data: &[u8], offset: usize) -> Option<u16> {
array(data, offset).map(u16::from_be_bytes)
}
#[inline]
pub(crate) fn u32_le(data: &[u8], offset: usize) -> Option<u32> {
array(data, offset).map(u32::from_le_bytes)
}
#[inline]
pub(crate) fn u32_be(data: &[u8], offset: usize) -> Option<u32> {
array(data, offset).map(u32::from_be_bytes)
}
#[inline]
pub(crate) fn u64_le(data: &[u8], offset: usize) -> Option<u64> {
array(data, offset).map(u64::from_le_bytes)
}
#[inline]
pub(crate) fn u64_be(data: &[u8], offset: usize) -> Option<u64> {
array(data, offset).map(u64::from_be_bytes)
}
#[inline]
pub(crate) fn to_usize(value: u64) -> Option<usize> {
usize::try_from(value).ok()
}
#[inline]
pub(crate) fn to_u64(value: usize) -> u64 {
u64::try_from(value).unwrap_or(u64::MAX)
}
#[cfg(test)]
#[allow(clippy::arithmetic_side_effects)] mod tests {
use super::*;
#[test]
fn readers_reject_out_of_range() {
let data = [1u8, 2, 3, 4, 5, 6, 7, 8];
assert_eq!(u32_le(&data, 0), Some(0x0403_0201));
assert_eq!(u32_be(&data, 4), Some(0x0506_0708));
assert_eq!(u16_be(&data, 6), Some(0x0708));
assert_eq!(u16_le(&data, 7), None);
assert_eq!(u64_le(&data, 0), Some(0x0807_0605_0403_0201));
assert_eq!(u64_be(&data, 1), None);
assert_eq!(bytes(&data, usize::MAX, 2), None);
assert_eq!(bytes(&data, 8, 0), Some(&[][..]));
}
}