You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

351 lines
7.5 KiB

//! Primitive data reading functions.
use half::f16;
use std::io::{self, Read};
/// Reads an [`i8`] from a [`&[u8]`][slice].
pub const fn i8x(b: &[u8], p: usize) -> i8 {
i8::from_ne_bytes([b[p]])
}
/// Reads a [`u8`] from a [`&[u8]`][slice].
pub const fn u8x(b: &[u8], p: usize) -> u8 {
b[p]
}
/// Reads an [`i16`] in big-endian order from a [`&[u8]`][slice].
pub const fn i16be(b: &[u8], p: usize) -> i16 {
i16::from_be_bytes([b[p], b[p + 1]])
}
/// Reads a [`u16`] in big-endian order from a [`&[u8]`][slice].
pub const fn u16be(b: &[u8], p: usize) -> u16 {
u16::from_be_bytes([b[p], b[p + 1]])
}
/// Reads an [`i32`] in big-endian order from a [`&[u8]`][slice].
pub const fn i32be(b: &[u8], p: usize) -> i32 {
i32::from_be_bytes([b[p], b[p + 1], b[p + 2], b[p + 3]])
}
/// Reads a [`u32`] in big-endian order from a [`&[u8]`][slice].
pub const fn u32be(b: &[u8], p: usize) -> u32 {
u32::from_be_bytes([b[p], b[p + 1], b[p + 2], b[p + 3]])
}
/// Reads an [`f16`] in big-endian order from a [`&[u8]`][slice].
pub fn f16be(b: &[u8], p: usize) -> f16 {
f16::from_be_bytes([b[p], b[p + 1]])
}
/// Reads an [`f32`] in big-endian order from a [`&[u8]`][slice].
pub fn f32be(b: &[u8], p: usize) -> f32 {
f32::from_be_bytes([b[p], b[p + 1], b[p + 2], b[p + 3]])
}
/// Reads an [`f64`] in big-endian order from a [`&[u8]`][slice].
pub fn f64be(b: &[u8], p: usize) -> f64 {
f64::from_be_bytes([
b[p],
b[p + 1],
b[p + 2],
b[p + 3],
b[p + 4],
b[p + 5],
b[p + 6],
b[p + 7],
])
}
/// Reads an [`i16`] in little-endian order from a [`&[u8]`][slice].
pub const fn i16le(b: &[u8], p: usize) -> i16 {
i16::from_le_bytes([b[p], b[p + 1]])
}
/// Reads a [`u16`] in little-endian order from a [`&[u8]`][slice].
pub const fn u16le(b: &[u8], p: usize) -> u16 {
u16::from_le_bytes([b[p], b[p + 1]])
}
/// Reads an [`i32`] in little-endian order from a [`&[u8]`][slice].
pub const fn i32le(b: &[u8], p: usize) -> i32 {
i32::from_le_bytes([b[p], b[p + 1], b[p + 2], b[p + 3]])
}
/// Reads a [`u32`] in little-endian order from a [`&[u8]`][slice].
pub const fn u32le(b: &[u8], p: usize) -> u32 {
u32::from_le_bytes([b[p], b[p + 1], b[p + 2], b[p + 3]])
}
/// Reads an [`f16`] in little-endian order from a [`&[u8]`][slice].
pub fn f16le(b: &[u8], p: usize) -> f16 {
f16::from_le_bytes([b[p], b[p + 1]])
}
/// Reads an [`f32`] in little-endian order from a [`&[u8]`][slice].
pub fn f32le(b: &[u8], p: usize) -> f32 {
f32::from_le_bytes([b[p], b[p + 1], b[p + 2], b[p + 3]])
}
/// Reads an [`f64`] in little-endian order from a [`&[u8]`][slice].
pub fn f64le(b: &[u8], p: usize) -> f64 {
f64::from_le_bytes([
b[p],
b[p + 1],
b[p + 2],
b[p + 3],
b[p + 4],
b[p + 5],
b[p + 6],
b[p + 7],
])
}
/// Reads a sequence of `N` `step`-sized chunks using `v` as a buffer
/// for output and `f` as a mapping function, beginning at `beg` in
/// `b`.
pub fn array<T, const N: usize>(
f: impl Fn(&[u8], usize) -> T, b: &[u8], mut v: [T; N], step: usize,
beg: usize,
) -> [T; N] {
for (p, v) in (beg..beg + N * step).step_by(step).zip(v.iter_mut()) {
*v = f(b, p);
}
v
}
/// Reads exactly `size` bytes from `rd`.
pub fn hunk(rd: &mut impl Read, size: usize) -> io::Result<Vec<u8>> {
let mut data = Vec::with_capacity(size);
unsafe {
data.set_len(size);
}
rd.read_exact(&mut data)?;
Ok(data)
}
#[rustfmt::skip]
macro_rules! bits_impl {
($t:ty, $be:ident, $le:ident) => {
#[doc = concat!(
"Reads `width` bits from `b` starting at bit `cr_bit` into one [`",
stringify!($t), "`] most significant bit first.\n",
"\n",
"# Errors\n",
"\n",
"This function will return `None` if there are not enough bits left ",
"in the buffer."
)]
#[inline]
pub const fn $be(
b: &[u8], cr_bit: usize, mut width: usize,
) -> Option<$t> {
if width == 0 {
return Some(0);
}
let last = (cr_bit + width - 1) / 8;
if last >= b.len() {
return None;
}
let mut byte_ptr = cr_bit / 8;
let mut bits_ptr = cr_bit % 8;
let mut res = 0;
while width > 0 {
width -= 1;
res <<= 1;
if b[byte_ptr] & 1 << bits_ptr != 0 {
res |= 1;
}
bits_ptr += 1;
if bits_ptr > 7 {
bits_ptr = 0;
byte_ptr += 1;
}
}
Some(res)
}
#[doc = concat!(
"The same as [`", stringify!($be), "`], but least-significant bit ",
"first.\n",
"\n",
"# Errors\n",
"\n",
"This function will return [`None`] if there are not enough bits ",
"left in the buffer."
)]
#[inline]
pub const fn $le(
b: &[u8], cr_bit: usize, mut width: usize,
) -> Option<$t> {
match width {
| 0 => Some(0),
| 1 => {
let byte = cr_bit / 8;
if byte < b.len() {
let bitn = cr_bit % 8;
Some(if b[byte] & 1 << bitn != 0 { 1 } else { 0 })
} else {
None
}
}
| _ => {
let last = (cr_bit + width - 1) / 8;
if last >= b.len() {
return None;
}
let mut byte_ptr = cr_bit / 8;
let mut bits_ptr = cr_bit % 8;
let mut res = 0;
let mut bit = 1;
while width > 0 {
width -= 1;
if b[byte_ptr] & 1 << bits_ptr != 0 {
res |= bit;
}
bit <<= 1;
bits_ptr += 1;
if bits_ptr > 7 {
bits_ptr = 0;
byte_ptr += 1;
}
}
Some(res)
}
}
}
};
}
bits_impl!(u8, bbe_u8, ble_u8);
bits_impl!(u16, bbe_u16, ble_u16);
bits_impl!(u32, bbe_u32, ble_u32);
bits_impl!(u64, bbe_u64, ble_u64);
bits_impl!(usize, bbe_usz, ble_usz);
#[test]
fn bit_tests() {
const INPUT: &[u8] = &[
0b01100101, 0b10101010, 0b00010000, 0b00000000, 0b11111111, 0b11100001,
0b10101100, 0b00110011, 0b10100101, 0b11100000, 0b00000111, 0b00000001,
0b11001010, 0b10101111, 0b00101011, 0b01101010, 0b11010101, 0b10100011,
0b01010101, 0b11000001,
];
let mut p = 0;
let n = bbe_u8(INPUT, p, 3).unwrap();
assert_eq!(n, 0b101);
p += 3;
let n = bbe_u64(INPUT, p, 63).unwrap();
assert_eq!(
n,
0b001100101010100001000000000001111111110000111001101011100110010,
);
p += 63;
let n = bbe_u8(INPUT, p, 4).unwrap();
assert_eq!(n, 0b1001);
p += 4;
let n = bbe_u8(INPUT, p, 7).unwrap();
assert_eq!(n, 0b0100000);
p += 7;
let n = bbe_u32(INPUT, p, 17).unwrap();
assert_eq!(n, 0b11111100000100000);
p += 17;
let n = bbe_u32(INPUT, p, 27).unwrap();
assert_eq!(n, 0b000101001111110101110101000);
p += 27;
let n = bbe_u64(INPUT, p, 33).unwrap();
assert_eq!(n, 0b101011010101011110001011010101010);
p += 33;
let n = bbe_usz(INPUT, p, 6).unwrap();
assert_eq!(n, 0b000011);
p += 6;
assert!(bbe_u8(INPUT, p, 1).is_none());
assert!(bbe_u8(INPUT, p, 2).is_none());
p = 0;
let n = ble_u8(INPUT, 0, 3).unwrap();
assert_eq!(n, 0b101);
p += 3;
let n = ble_u64(INPUT, p, 59).unwrap();
assert_eq!(
n,
0b11001110101100111000011111111100000000000100001010101001100,
);
p += 59;
let n = ble_u8(INPUT, p, 1).unwrap();
assert_eq!(n, 0b0);
p += 1;
let n = ble_u8(INPUT, p, 1).unwrap();
assert_eq!(n, 0b0);
p += 1;
let n = ble_u8(INPUT, p, 1).unwrap();
assert_eq!(n, 0b1);
p += 1;
let n = ble_u8(INPUT, p, 1).unwrap();
assert_eq!(n, 0b0);
p += 1;
let n = ble_u8(INPUT, p, 4).unwrap();
assert_eq!(n, 0b1001);
p += 4;
let n = ble_u8(INPUT, p, 7).unwrap();
assert_eq!(n, 0b0000010);
p += 7;
let n = ble_u32(INPUT, p, 17).unwrap();
assert_eq!(n, 0b00000100000111111);
p += 17;
let n = ble_u32(INPUT, p, 27).unwrap();
assert_eq!(n, 0b000101011101011111100101000);
p += 27;
let n = ble_u64(INPUT, p, 33).unwrap();
assert_eq!(n, 0b010101010110100011110101010110101);
p += 33;
let n = ble_usz(INPUT, p, 6).unwrap();
assert_eq!(n, 0b110000);
p += 6;
assert!(ble_u8(INPUT, p, 1).is_none());
assert!(ble_u8(INPUT, p, 2).is_none());
}
// EOF