const BUFFER_SIZE: usize = 5_242_880;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SeekOrigin {
Begin,
Current,
End,
}
#[derive(Debug, Default)]
pub struct TsStreamBuffer {
buffer: Vec<u8>,
position: usize,
skip_bits: i32,
skipped_bytes: usize,
transfer_length: usize,
}
impl TsStreamBuffer {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn length(&self) -> u64 {
u64::try_from(self.buffer.len()).unwrap_or(u64::MAX)
}
#[must_use]
pub fn position(&self) -> u64 {
u64::try_from(self.position).unwrap_or(u64::MAX)
}
#[must_use]
pub fn transfer_length(&self) -> u64 {
u64::try_from(self.transfer_length).unwrap_or(u64::MAX)
}
pub const fn add_transfer_length(&mut self, length: usize) {
self.transfer_length = self.transfer_length.wrapping_add(length);
}
#[must_use]
pub fn content(&self) -> &[u8] {
&self.buffer
}
#[must_use]
pub fn data_bit_stream_remain(&self) -> i64 {
let len = i64::try_from(self.buffer.len()).unwrap_or(i64::MAX);
let pos = i64::try_from(self.position).unwrap_or(i64::MAX);
len.wrapping_sub(pos).wrapping_mul(8).wrapping_sub(i64::from(self.skip_bits))
}
#[must_use]
pub fn data_bit_stream_remain_bytes(&self) -> i64 {
let len = i64::try_from(self.buffer.len()).unwrap_or(i64::MAX);
let pos = i64::try_from(self.position).unwrap_or(i64::MAX);
len.wrapping_sub(pos)
}
pub fn add(&mut self, buffer: &[u8], offset: usize, length: usize) {
self.transfer_length = self.transfer_length.wrapping_add(length);
let length = if self.buffer.len().saturating_add(length) >= BUFFER_SIZE {
BUFFER_SIZE.saturating_sub(self.buffer.len())
} else {
length
};
if length == 0 {
return;
}
if let Some(src) = buffer.get(offset..offset.saturating_add(length)) {
self.buffer.extend_from_slice(src);
}
}
pub fn seek(&mut self, offset: i64, origin: SeekOrigin) {
let base = match origin {
SeekOrigin::Begin => 0_i64,
SeekOrigin::Current => i64::try_from(self.position).unwrap_or(i64::MAX),
SeekOrigin::End => i64::try_from(BUFFER_SIZE).unwrap_or(i64::MAX),
};
let target = base.wrapping_add(offset);
self.position = usize::try_from(target).unwrap_or(0);
}
pub fn reset(&mut self) {
self.buffer.clear();
self.transfer_length = 0;
}
pub const fn begin_read(&mut self) {
self.skip_bits = 0;
self.skipped_bytes = 0;
self.position = 0;
}
fn raw_byte_at(&self, p: usize) -> u8 {
self.buffer.get(p).copied().unwrap_or(if p < BUFFER_SIZE { 0x00 } else { 0xFF })
}
#[must_use]
pub fn read_byte(&mut self, skip_h26x_emulation_byte: bool) -> u8 {
let p = self.position;
let mut temp = self.raw_byte_at(p);
self.position = p.saturating_add(1);
if skip_h26x_emulation_byte
&& temp == 0x03
&& let (Some(p2), Some(p1)) = (p.checked_sub(2), p.checked_sub(1))
&& self.raw_byte_at(p2) == 0x00
&& self.raw_byte_at(p1) == 0x00
{
temp = self.raw_byte_at(p.saturating_add(1));
self.position = p.saturating_add(2);
self.skipped_bytes = self.skipped_bytes.saturating_add(1);
}
temp
}
#[must_use]
pub fn read_bytes(&mut self, bytes: usize) -> Option<Vec<u8>> {
let end = self.position.checked_add(bytes)?;
if end >= self.buffer.len() {
return None;
}
let value: Vec<u8> = self.buffer.iter().skip(self.position).take(bytes).copied().collect();
self.position = end;
Some(value)
}
fn advance_bits(&mut self, pos: usize, bits: usize) {
let bits = i32::try_from(bits).unwrap_or(i32::MAX);
self.skip_bits = self.skip_bits.wrapping_add(bits);
let whole = usize::try_from(self.skip_bits.wrapping_shr(3)).unwrap_or(0);
self.position = pos.saturating_add(whole).saturating_add(self.skipped_bytes);
self.skip_bits = self.skip_bits.wrapping_rem(8);
}
#[must_use]
pub fn read_bool(&mut self, skip_h26x_emulation_byte: bool) -> bool {
let pos = self.position;
self.skipped_bytes = 0;
if pos == self.buffer.len() {
return false;
}
let data = self.read_byte(skip_h26x_emulation_byte);
let sc = 8_i32.wrapping_sub(self.skip_bits).wrapping_sub(1);
let mask = 1_u32.wrapping_shl(sc.cast_unsigned());
let value = (u32::from(data) & mask) != 0;
self.advance_bits(pos, 1);
value
}
fn load_be_bytes(&mut self, pos: usize, bytes: usize, skip_h26x_emulation_byte: bool) -> u32 {
let mut shift = u32::try_from(bytes).unwrap_or(0).saturating_sub(1).wrapping_mul(8);
let mut data: u32 = 0;
for i in 0..bytes {
if pos.saturating_add(i) >= self.buffer.len() {
break;
}
let byte = u32::from(self.read_byte(skip_h26x_emulation_byte));
data = data.wrapping_add(byte.wrapping_shl(shift));
shift = shift.wrapping_sub(8);
}
data
}
#[must_use]
pub fn find_sync32(&mut self, sync: u32) -> bool {
let mut window: u32 = 0;
for _ in 0..self.length() {
window = window.wrapping_shl(8).wrapping_add(u32::from(self.read_byte(false)));
if window == sync {
return true;
}
}
false
}
#[must_use]
pub fn read_bits2(&mut self, bits: usize, skip_h26x_emulation_byte: bool) -> u16 {
let pos = self.position;
self.skipped_bytes = 0;
let data = self.load_be_bytes(pos, 2, skip_h26x_emulation_byte);
let count = i32::try_from(bits).unwrap_or(i32::MAX);
let end = self.skip_bits.wrapping_add(count);
let mut value: u16 = 0;
let mut i = self.skip_bits;
while i < end {
let idx = 16_i32.wrapping_sub(i).wrapping_sub(1);
let bit = if (0..16).contains(&idx) {
u16::from((data.wrapping_shr(idx.cast_unsigned()) & 1) == 1)
} else {
0
};
value = value.wrapping_shl(1).wrapping_add(bit);
i = i.wrapping_add(1);
}
self.advance_bits(pos, bits);
value
}
#[must_use]
pub fn read_bits4(&mut self, bits: usize, skip_h26x_emulation_byte: bool) -> u32 {
let pos = self.position;
self.skipped_bytes = 0;
let data = self.load_be_bytes(pos, 4, skip_h26x_emulation_byte);
let count = i32::try_from(bits).unwrap_or(i32::MAX);
let end = self.skip_bits.wrapping_add(count);
let mut value: u32 = 0;
let mut i = self.skip_bits;
while i < end {
let idx = 32_i32.wrapping_sub(i).wrapping_sub(1);
let bit =
if (0..32).contains(&idx) { data.wrapping_shr(idx.cast_unsigned()) & 1 } else { 0 };
value = value.wrapping_shl(1).wrapping_add(bit);
i = i.wrapping_add(1);
}
self.advance_bits(pos, bits);
value
}
#[must_use]
pub fn read_bits8(&mut self, bits: usize, skip_h26x_emulation_byte: bool) -> u64 {
let pos = self.position;
self.skipped_bytes = 0;
let data = self.load_be_bytes(pos, 4, skip_h26x_emulation_byte);
let data2 = self.load_be_bytes(pos, 4, skip_h26x_emulation_byte);
let window = u64::from(data).wrapping_shl(32).wrapping_add(u64::from(data2));
let count = i32::try_from(bits).unwrap_or(i32::MAX);
let end = self.skip_bits.wrapping_add(count);
let mut value: u64 = 0;
let mut i = self.skip_bits;
while i < end {
let idx = 64_i32.wrapping_sub(i).wrapping_sub(1);
let bit = if (0..64).contains(&idx) {
window.wrapping_shr(idx.cast_unsigned()) & 1
} else {
0
};
value = value.wrapping_shl(1).wrapping_add(bit);
i = i.wrapping_add(1);
}
self.advance_bits(pos, bits);
value
}
pub fn bs_skip_bits(&mut self, bits: usize, skip_h26x_emulation_byte: bool) {
let count = bits.div_ceil(16);
let mut bits_read: usize = 0;
for _ in 0..count {
let to_read = bits.wrapping_sub(bits_read).min(16);
let _ = self.read_bits2(to_read, skip_h26x_emulation_byte);
bits_read = bits_read.wrapping_add(to_read);
}
}
pub fn bs_skip_next_byte(&mut self) {
if self.skip_bits > 0 {
let bits = usize::try_from(8_i32.wrapping_sub(self.skip_bits)).unwrap_or(0);
self.bs_skip_bits(bits, false);
}
}
pub const fn bs_reset_bits(&mut self) {
self.skip_bits = 0;
}
pub fn bs_skip_bytes(&mut self, bytes: i32, skip_h26x_emulation_byte: bool) {
if bytes > 0 {
for _ in 0..bytes {
let _ = self.read_byte(skip_h26x_emulation_byte);
}
} else {
let pos = self.position;
let delta = self.skip_bits.wrapping_shr(3).wrapping_add(bytes);
let target = i64::try_from(pos).unwrap_or(i64::MAX).wrapping_add(i64::from(delta));
self.position = usize::try_from(target).unwrap_or(0);
}
}
fn count_exp_leading_zeroes(&mut self, skip_h26x_emulation_byte: bool) -> u8 {
let mut leading_zeroes: u8 = 0;
while self.data_bit_stream_remain() > 0 && !self.read_bool(skip_h26x_emulation_byte) {
leading_zeroes = leading_zeroes.wrapping_add(1);
}
leading_zeroes
}
#[must_use]
pub fn read_exp(&mut self, skip_h26x_emulation_byte: bool) -> u32 {
let leading_zeroes = self.count_exp_leading_zeroes(skip_h26x_emulation_byte);
let info = 1_u32.wrapping_shl(u32::from(leading_zeroes));
let extra = self.read_bits4(usize::from(leading_zeroes), skip_h26x_emulation_byte);
info.wrapping_sub(1).wrapping_add(extra)
}
pub fn skip_exp(&mut self, skip_h26x_emulation_byte: bool) {
let leading_zeroes = self.count_exp_leading_zeroes(skip_h26x_emulation_byte);
self.bs_skip_bits(usize::from(leading_zeroes), skip_h26x_emulation_byte);
}
pub fn skip_exp_multi(&mut self, num: usize, skip_h26x_emulation_byte: bool) {
for _ in 0..num {
self.skip_exp(skip_h26x_emulation_byte);
}
}
}
#[cfg(test)]
pub mod bits {
use super::TsStreamBuffer;
pub(crate) fn buf(data: &[u8]) -> TsStreamBuffer {
let mut b = TsStreamBuffer::new();
b.add(data, 0, data.len());
b.begin_read();
b
}
pub(crate) fn pack(fields: &[(u64, u32)]) -> Vec<u8> {
let mut bytes = Vec::new();
let mut cur: u8 = 0;
let mut nbits: u32 = 0;
for &(val, width) in fields {
let mut b = width;
while b > 0 {
b = b.wrapping_sub(1);
let bit = u8::try_from(val.wrapping_shr(b) & 1).unwrap_or(0);
cur = cur.wrapping_shl(1).wrapping_add(bit);
nbits = nbits.wrapping_add(1);
if nbits == 8 {
bytes.push(cur);
cur = 0;
nbits = 0;
}
}
}
if nbits > 0 {
bytes.push(cur.wrapping_shl(8_u32.wrapping_sub(nbits)));
}
bytes
}
#[test]
fn pack_handles_aligned_and_partial_inputs() {
assert_eq!(pack(&[(0xABCD, 16)]), vec![0xAB, 0xCD]);
assert_eq!(pack(&[(0xABC, 12)]), vec![0xAB, 0xC0]);
}
#[test]
fn buf_is_readable_from_its_first_byte() {
let mut b = buf(&[0xAB, 0xCD]);
assert_eq!(b.length(), 2);
assert_eq!(b.read_bits4(16, false), 0xABCD);
}
}
#[cfg(test)]
mod tests {
use proptest::prelude::{any, prop_assert, prop_assert_eq, proptest};
use super::bits::buf;
use super::{BUFFER_SIZE, SeekOrigin, TsStreamBuffer};
fn pack_bits(bits: &[bool]) -> Vec<u8> {
let mut bytes = Vec::new();
let mut cur: u8 = 0;
let mut count: u32 = 0;
for &bit in bits {
cur = cur.wrapping_shl(1).wrapping_add(u8::from(bit));
count = count.wrapping_add(1);
if count == 8 {
bytes.push(cur);
cur = 0;
count = 0;
}
}
if count > 0 {
bytes.push(cur.wrapping_shl(8_u32.wrapping_sub(count)));
}
bytes
}
fn encode_ue(v: u32) -> Vec<u8> {
let code_num = v.wrapping_add(1);
let n = 31_u32.wrapping_sub(code_num.leading_zeros());
let mut bits: Vec<bool> = vec![false; usize::try_from(n).unwrap()];
for i in (0..=n).rev() {
bits.push((code_num.wrapping_shr(i) & 1) == 1);
}
pack_bits(&bits)
}
#[test]
fn new_is_empty() {
let b = TsStreamBuffer::new();
assert_eq!(b.length(), 0);
assert_eq!(b.position(), 0);
assert_eq!(b.transfer_length(), 0);
assert_eq!(b.data_bit_stream_remain(), 0);
assert_eq!(b.data_bit_stream_remain_bytes(), 0);
}
#[test]
fn default_is_empty() {
let b = TsStreamBuffer::default();
assert_eq!(b.length(), 0);
assert_eq!(b.position(), 0);
}
#[test]
fn add_appends_and_tracks_transfer_length() {
let mut b = TsStreamBuffer::new();
b.add(&[0x01, 0x02, 0x03], 0, 3);
assert_eq!(b.length(), 3);
assert_eq!(b.transfer_length(), 3);
b.add(&[0x04, 0x05], 0, 2);
assert_eq!(b.length(), 5);
assert_eq!(b.transfer_length(), 5);
}
#[test]
fn add_transfer_length_bumps_count_without_content() {
let mut b = TsStreamBuffer::new();
b.add(&[0x01, 0x02], 0, 2);
assert_eq!(b.length(), 2);
assert_eq!(b.transfer_length(), 2);
b.add_transfer_length(100);
assert_eq!(b.length(), 2);
assert_eq!(b.transfer_length(), 102);
b.add_transfer_length(0);
assert_eq!(b.transfer_length(), 102);
}
#[test]
fn content_exposes_stored_bytes() {
let mut b = TsStreamBuffer::new();
assert!(b.content().is_empty());
b.add(&[0xDE, 0xAD, 0xBE, 0xEF], 1, 2);
assert_eq!(b.content(), [0xAD, 0xBE]);
b.add_transfer_length(50);
assert_eq!(b.content(), [0xAD, 0xBE]);
b.reset();
assert!(b.content().is_empty());
}
#[test]
fn add_honors_offset() {
let mut b = TsStreamBuffer::new();
b.add(&[0x00, 0x01, 0x02, 0x03, 0x04], 2, 2);
assert_eq!(b.length(), 2);
b.begin_read();
assert!(!b.read_bool(false));
assert!(!b.read_bool(false));
}
#[test]
fn add_zero_length_is_noop() {
let mut b = TsStreamBuffer::new();
b.add(&[], 0, 0);
assert_eq!(b.length(), 0);
assert_eq!(b.transfer_length(), 0);
b.add(&[0xAB, 0xCD], 0, 0);
assert_eq!(b.length(), 0);
assert_eq!(b.transfer_length(), 0);
}
#[test]
fn add_short_source_stores_nothing_but_counts_transfer() {
let mut b = TsStreamBuffer::new();
b.add(&[0x01, 0x02], 0, 5);
assert_eq!(b.length(), 0);
assert_eq!(b.transfer_length(), 5);
}
#[test]
fn add_clamps_to_buffer_size() {
let mut b = TsStreamBuffer::new();
let big = vec![0x5A_u8; BUFFER_SIZE.saturating_add(16)];
b.add(&big, 0, big.len());
assert_eq!(b.length(), u64::try_from(BUFFER_SIZE).unwrap());
assert_eq!(b.transfer_length(), u64::try_from(BUFFER_SIZE.saturating_add(16)).unwrap());
b.add(&[0x99], 0, 1);
assert_eq!(b.length(), u64::try_from(BUFFER_SIZE).unwrap());
assert_eq!(b.transfer_length(), u64::try_from(BUFFER_SIZE.saturating_add(17)).unwrap());
}
#[test]
fn reset_clears_content_and_transfer_length() {
let mut b = TsStreamBuffer::new();
b.add(&[0x01, 0x02, 0x03], 0, 3);
b.reset();
assert_eq!(b.length(), 0);
assert_eq!(b.transfer_length(), 0);
b.add(&[0x04], 0, 1);
assert_eq!(b.length(), 1);
}
#[test]
fn seek_begin_current_end_and_clamp() {
let mut b = buf(&[0x00, 0x11, 0x22, 0x33]);
b.seek(3, SeekOrigin::Begin);
assert_eq!(b.position(), 3);
b.seek(2, SeekOrigin::Current);
assert_eq!(b.position(), 5);
b.seek(-1, SeekOrigin::End);
assert_eq!(b.position(), u64::try_from(BUFFER_SIZE).unwrap().saturating_sub(1));
b.seek(-100, SeekOrigin::Begin);
assert_eq!(b.position(), 0);
}
#[test]
fn begin_read_rewinds() {
let mut b = buf(&[0xFF, 0xFF]);
let _ = b.read_bool(false);
b.seek(2, SeekOrigin::Begin);
b.begin_read();
assert_eq!(b.position(), 0);
}
#[test]
fn remain_counts_bits_and_bytes() {
let b = buf(&[0xAA, 0xBB, 0xCC, 0xDD]);
assert_eq!(b.data_bit_stream_remain(), 32);
assert_eq!(b.data_bit_stream_remain_bytes(), 4);
}
#[test]
fn remain_is_negative_past_content() {
let mut b = buf(&[0xAA]);
b.seek(5, SeekOrigin::Begin);
assert_eq!(b.data_bit_stream_remain(), -32);
assert_eq!(b.data_bit_stream_remain_bytes(), -4);
}
#[test]
fn read_byte_reads_sequentially() {
let mut b = buf(&[0x12, 0x34, 0x56]);
assert_eq!(b.read_byte(false), 0x12);
assert_eq!(b.read_byte(false), 0x34);
assert_eq!(b.read_byte(false), 0x56);
}
#[test]
fn read_bytes_reads_a_slice_and_advances() {
let mut b = buf(&[0x0B, 0x77, 0x24, 0x40, 0xE1]);
assert_eq!(b.read_bytes(2).as_deref(), Some(&[0x0B, 0x77][..]));
assert_eq!(b.position(), 2);
assert_eq!(b.read_bytes(2).as_deref(), Some(&[0x24, 0x40][..]));
assert_eq!(b.position(), 4);
}
#[test]
fn read_bytes_at_or_past_end_is_none() {
let mut b = buf(&[0x0B, 0x77, 0x24, 0x40]);
assert_eq!(b.read_bytes(4), None);
assert_eq!(b.position(), 0);
assert_eq!(b.read_bytes(3).as_deref(), Some(&[0x0B, 0x77, 0x24][..]));
assert_eq!(b.position(), 3);
assert_eq!(b.read_bytes(5), None);
assert_eq!(b.position(), 3);
}
#[test]
fn read_bytes_zero_length_when_in_content_is_empty() {
let mut b = buf(&[0x0B, 0x77]);
assert_eq!(b.read_bytes(0).as_deref(), Some(&[][..]));
assert_eq!(b.position(), 0);
b.seek(2, SeekOrigin::Begin);
assert_eq!(b.read_bytes(0), None);
}
#[test]
fn read_bytes_overflow_is_none() {
let mut b = buf(&[0x0B, 0x77, 0x24]);
b.seek(1, SeekOrigin::Begin);
assert_eq!(b.read_bytes(usize::MAX), None);
assert_eq!(b.position(), 1);
}
#[test]
fn read_byte_no_skip_keeps_emulation_byte() {
let mut b = buf(&[0x00, 0x00, 0x03, 0x5A]);
b.seek(2, SeekOrigin::Begin);
assert_eq!(b.read_byte(false), 0x03);
}
#[test]
fn read_byte_skips_emulation_byte_after_double_zero() {
let mut b = buf(&[0x00, 0x00, 0x03, 0x5A]);
b.seek(2, SeekOrigin::Begin);
assert_eq!(b.read_byte(true), 0x5A);
assert_eq!(b.position(), 4);
}
#[test]
fn read_byte_no_skip_when_prefix_not_double_zero() {
let mut b = buf(&[0x01, 0x00, 0x03, 0x5A]);
b.seek(2, SeekOrigin::Begin);
assert_eq!(b.read_byte(true), 0x03);
let mut b = buf(&[0x00, 0x01, 0x03, 0x5A]);
b.seek(2, SeekOrigin::Begin);
assert_eq!(b.read_byte(true), 0x03);
}
#[test]
fn read_byte_no_skip_when_too_close_to_start() {
let mut b = buf(&[0x03, 0x5A]);
assert_eq!(b.read_byte(true), 0x03);
let mut b = buf(&[0x00, 0x03, 0x5A]);
b.seek(1, SeekOrigin::Begin);
assert_eq!(b.read_byte(true), 0x03);
}
#[test]
fn read_bool_reads_bits_msb_first() {
let mut b = buf(&[0xAC]);
let bits: Vec<bool> = (0..8).map(|_| b.read_bool(false)).collect();
assert_eq!(bits, vec![true, false, true, false, true, true, false, false]);
assert_eq!(b.position(), 1);
}
#[test]
fn read_bool_at_end_is_false() {
let mut b = buf(&[0xFF]);
for _ in 0..8 {
assert!(b.read_bool(false));
}
assert!(!b.read_bool(false));
assert_eq!(b.position(), 1);
}
#[test]
fn read_bool_past_content_reads_zero_fill() {
let mut b = buf(&[0xFF]);
b.seek(10, SeekOrigin::Begin);
assert!(!b.read_bool(false));
}
#[test]
fn read_bool_at_eof_sentinel_reads_one_fill() {
let mut b = buf(&[0xAA]);
b.seek(i64::try_from(BUFFER_SIZE).unwrap(), SeekOrigin::Begin);
assert!(b.read_bool(false));
}
#[test]
fn read_bool_through_emulation_byte() {
let mut b = buf(&[0x00, 0x00, 0x03, 0x80]);
b.seek(2, SeekOrigin::Begin);
assert!(b.read_bool(true));
}
#[test]
fn read_bits4_reads_msb_first() {
let mut b = buf(&[0xAC]);
assert_eq!(b.read_bits4(3, false), 0b101); assert_eq!(b.read_bits4(5, false), 12); assert_eq!(b.position(), 1);
}
#[test]
fn read_bits4_single_byte_and_full_widths() {
let mut b = buf(&[0xAC]);
assert_eq!(b.read_bits4(8, false), 0xAC);
let mut b = buf(&[0x12, 0x34, 0x56, 0x78]);
assert_eq!(b.read_bits4(32, false), 0x1234_5678);
}
#[test]
fn read_bits4_truncated_window_zero_fills() {
let mut b = buf(&[0x12, 0x34]);
assert_eq!(b.read_bits4(32, false), 0x1234_0000);
}
#[test]
fn read_bits2_reads_msb_first() {
let mut b = buf(&[0xAC]);
assert_eq!(b.read_bits2(4, false), 0xA);
assert_eq!(b.read_bits2(4, false), 0xC);
let mut b = buf(&[0xAC]);
assert_eq!(b.read_bits2(8, false), 0xAC);
let mut b = buf(&[0x12, 0x34]);
assert_eq!(b.read_bits2(16, false), 0x1234);
}
#[test]
fn find_sync32_stops_just_past_the_word_it_finds() {
let mut b = buf(&[0x11, 0x22, 0xDE, 0xAD, 0xBE, 0xEF, 0x99]);
assert!(b.find_sync32(0xDEAD_BEEF));
assert_eq!(b.position(), 6);
assert_eq!(b.read_byte(false), 0x99);
let mut b = buf(&[0xDE, 0xAD, 0xBE]);
assert!(!b.find_sync32(0xDEAD_BEEF));
assert_eq!(b.position(), 3);
assert!(!buf(&[]).find_sync32(0xDEAD_BEEF));
}
#[test]
fn read_bits2_past_window_zero_extends() {
let mut b = buf(&[0xFF, 0xFF]);
assert_eq!(b.read_bits2(3, false), 0b111);
assert_eq!(b.read_bits2(16, false), 0xFFF8);
let mut b = buf(&[0xFF, 0xFF]);
assert_eq!(b.read_bits2(33, false), 0x0000);
}
#[test]
fn read_bits8_full_and_partial_widths() {
let bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF];
assert_eq!(buf(&bytes).read_bits8(64, false), 0x0123_4567_89AB_CDEF);
assert_eq!(buf(&bytes).read_bits8(8, false), 0x01);
assert_eq!(buf(&bytes).read_bits8(16, false), 0x0123);
assert_eq!(buf(&bytes).read_bits8(33, false), 0x0246_8ACF);
}
#[test]
fn read_bits8_truncated_window_zero_fills() {
let mut b = buf(&[0x12, 0x34]);
assert_eq!(b.read_bits8(16, false), 0x1234);
}
#[test]
fn read_bits8_past_window_contributes_zero() {
let bytes = [0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF];
let mut b = buf(&bytes);
let _ = b.read_bool(false);
assert_eq!(b.read_bits8(64, false), 0x0246_8ACF_1357_9BDE);
}
#[test]
fn read_bits4_unaligned_full_width_zero_fills() {
let mut b = buf(&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF]);
assert_eq!(b.read_bits4(3, false), 0b111);
assert_eq!(b.read_bits4(32, false), 0xFFFF_FFF8);
let mut b = buf(&[0xF2, 0x34, 0x56, 0x78, 0x9A]);
assert_eq!(b.read_bits4(3, false), 0b111);
assert_eq!(b.read_bits4(32, false), 0x91A2_B3C0); }
#[test]
fn bs_skip_bits_zero_is_noop() {
let mut b = buf(&[0xAC]);
b.bs_skip_bits(0, false);
assert_eq!(b.position(), 0);
assert!(b.read_bool(false)); }
#[test]
fn bs_skip_bits_within_and_across_bytes() {
let mut b = buf(&[0xAC, 0xFF]);
b.bs_skip_bits(5, false);
assert_eq!(b.read_bits4(3, false), 0b100);
let mut b = buf(&[0x00, 0x00, 0x00, 0xFF]);
b.bs_skip_bits(20, false);
assert_eq!(b.position(), 2);
assert_eq!(b.read_bits4(4, false), 0); }
#[test]
fn bs_skip_next_byte_aligns_then_is_noop() {
let mut b = buf(&[0xAC, 0x3C]);
let _ = b.read_bits4(3, false); b.bs_skip_next_byte();
assert_eq!(b.position(), 1);
b.bs_skip_next_byte(); assert_eq!(b.position(), 1);
assert_eq!(b.read_bits4(8, false), 0x3C);
}
#[test]
fn bs_reset_bits_clears_cursor_without_moving() {
let mut b = buf(&[0xAC]);
let _ = b.read_bits4(3, false);
b.bs_reset_bits();
assert_eq!(b.position(), 0);
assert_eq!(b.read_bits4(3, false), 0b101);
}
#[test]
fn bs_skip_bytes_positive_reads_forward() {
let mut b = buf(&[0x11, 0x22, 0x33, 0x44]);
b.bs_skip_bytes(3, false);
assert_eq!(b.position(), 3);
assert_eq!(b.read_bits4(8, false), 0x44);
}
#[test]
fn bs_skip_bytes_positive_honors_emulation() {
let mut b = buf(&[0x00, 0x00, 0x03, 0x5A, 0x99]);
b.seek(2, SeekOrigin::Begin);
b.bs_skip_bytes(1, true);
assert_eq!(b.position(), 4);
}
#[test]
fn bs_skip_bytes_nonpositive_repositions_and_clamps() {
let mut b = buf(&[0x11, 0x22, 0x33, 0x44, 0x55]);
b.seek(4, SeekOrigin::Begin);
b.bs_skip_bytes(-2, false);
assert_eq!(b.position(), 2);
b.bs_skip_bytes(0, false); assert_eq!(b.position(), 2);
b.bs_skip_bytes(-100, false); assert_eq!(b.position(), 0);
}
#[test]
fn read_exp_decodes_small_codes() {
let mut b = buf(&[0xA6, 0x40]);
assert_eq!(b.read_exp(false), 0);
assert_eq!(b.read_exp(false), 1);
assert_eq!(b.read_exp(false), 2);
assert_eq!(b.read_exp(false), 3);
}
#[test]
fn read_exp_decodes_code_with_suffix() {
let mut b = buf(&[0x38]);
assert_eq!(b.read_exp(false), 6);
}
#[test]
fn read_exp_all_zeros_exhausts_via_remain_guard() {
let mut b = buf(&[0x00]);
assert_eq!(b.read_exp(false), 255);
}
#[test]
fn read_exp_skips_emulation_byte() {
let mut b = buf(&[0x00, 0x00, 0x03, 0x80]);
b.seek(2, SeekOrigin::Begin);
assert_eq!(b.read_exp(true), 0);
let mut b = buf(&[0x00, 0x00, 0x03, 0x80]);
b.seek(2, SeekOrigin::Begin);
assert_ne!(b.read_exp(false), 0);
}
#[test]
fn read_bits4_skips_emulation_byte() {
let mut b = buf(&[0x00, 0x00, 0x03, 0xAB, 0xCD]);
b.seek(2, SeekOrigin::Begin);
assert_eq!(b.read_bits4(8, true), 0xAB);
assert_eq!(b.position(), 4);
}
#[test]
fn skip_exp_consumes_one_code() {
let mut b = buf(&[0xA6, 0x40]);
b.skip_exp(false); b.skip_exp(false); assert_eq!(b.read_exp(false), 2);
}
#[test]
fn skip_exp_multi_consumes_n_codes() {
let mut b = buf(&[0xA6, 0x40]);
b.skip_exp_multi(2, false);
assert_eq!(b.read_exp(false), 2);
let mut b = buf(&[0xA6, 0x40]);
b.skip_exp_multi(0, false);
assert_eq!(b.read_exp(false), 0);
}
#[test]
fn pack_bits_whole_and_partial_bytes() {
assert_eq!(pack_bits(&[true, false, true, false, true, false, true, false]), vec![0xAA]);
let mut bits = vec![true; 8];
bits.extend_from_slice(&[true, false, true, false]);
assert_eq!(pack_bits(&bits), vec![0xFF, 0xA0]);
}
proptest! {
#[test]
fn read_bool_reconstructs_bytes_msb_first(data in any::<Vec<u8>>()) {
let mut b = buf(&data);
for &expected in &data {
let mut got: u8 = 0;
for _ in 0..8 {
got = got.wrapping_shl(1).wrapping_add(u8::from(b.read_bool(false)));
}
prop_assert_eq!(got, expected);
}
prop_assert_eq!(b.position(), u64::try_from(data.len()).unwrap());
}
#[test]
fn reads_never_panic_on_arbitrary_input(data in any::<Vec<u8>>(), n in 0_usize..512) {
let mut b = buf(&data);
for _ in 0..n {
let _ = b.read_bool(true);
}
prop_assert!(b.position() <= u64::try_from(BUFFER_SIZE).unwrap());
}
#[test]
fn read_bytes_matches_slice_or_is_none(data in any::<Vec<u8>>(), n in 0_usize..600) {
let mut b = buf(&data);
let got = b.read_bytes(n);
if n < data.len() {
prop_assert_eq!(got.as_deref(), data.get(0..n));
prop_assert_eq!(b.position(), u64::try_from(n).unwrap());
} else {
prop_assert_eq!(got, None);
prop_assert_eq!(b.position(), 0);
}
}
#[test]
fn read_bits2_byte_at_a_time_reconstructs(data in any::<Vec<u8>>()) {
let mut b = buf(&data);
for &expected in &data {
prop_assert_eq!(b.read_bits2(8, false), u16::from(expected));
}
}
#[test]
fn read_bits4_byte_at_a_time_reconstructs(data in any::<Vec<u8>>()) {
let mut b = buf(&data);
for &expected in &data {
prop_assert_eq!(b.read_bits4(8, false), u32::from(expected));
}
}
#[test]
fn read_bits8_byte_at_a_time_reconstructs(data in any::<Vec<u8>>()) {
let mut b = buf(&data);
for &expected in &data {
prop_assert_eq!(b.read_bits8(8, false), u64::from(expected));
}
}
#[test]
fn read_bits2_matches_bit_by_bit(bytes in any::<[u8; 8]>(), n in 1_usize..=16) {
let mut whole = buf(&bytes);
let mut bitwise = buf(&bytes);
let mut acc: u16 = 0;
for _ in 0..n {
acc = acc.wrapping_shl(1).wrapping_add(u16::from(bitwise.read_bool(false)));
}
prop_assert_eq!(whole.read_bits2(n, false), acc);
}
#[test]
fn read_bits4_matches_bit_by_bit(bytes in any::<[u8; 8]>(), n in 1_usize..=32) {
let mut whole = buf(&bytes);
let mut bitwise = buf(&bytes);
let mut acc: u32 = 0;
for _ in 0..n {
acc = acc.wrapping_shl(1).wrapping_add(u32::from(bitwise.read_bool(false)));
}
prop_assert_eq!(whole.read_bits4(n, false), acc);
}
#[test]
fn read_bits8_matches_bit_by_bit(bytes in any::<[u8; 8]>(), n in 1_usize..=64) {
let mut whole = buf(&bytes);
let mut bitwise = buf(&bytes);
let mut acc: u64 = 0;
for _ in 0..n {
acc = acc.wrapping_shl(1).wrapping_add(u64::from(bitwise.read_bool(false)));
}
prop_assert_eq!(whole.read_bits8(n, false), acc);
}
#[test]
fn bs_skip_bits_matches_reading_bit_by_bit(bytes in any::<[u8; 8]>(), n in 0_usize..=48) {
let mut skipped = buf(&bytes);
let mut read = buf(&bytes);
skipped.bs_skip_bits(n, false);
for _ in 0..n {
let _ = read.read_bool(false);
}
prop_assert_eq!(skipped.position(), read.position());
prop_assert_eq!(skipped.read_bits8(16, false), read.read_bits8(16, false));
}
#[test]
fn read_exp_decodes_encoded_value(v in 0_u32..=2_000_000) {
let mut b = buf(&encode_ue(v));
prop_assert_eq!(b.read_exp(false), v);
}
#[test]
fn skip_exp_consumes_same_bits_as_read_exp(v in 0_u32..=2_000_000) {
let mut skipped = buf(&encode_ue(v));
let mut read = buf(&encode_ue(v));
skipped.skip_exp(false);
let _ = read.read_exp(false);
prop_assert_eq!(skipped.data_bit_stream_remain(), read.data_bit_stream_remain());
}
#[test]
fn read_exp_never_panics_on_arbitrary_input(data in any::<Vec<u8>>(), skip in any::<bool>()) {
let mut b = buf(&data);
let _ = b.read_exp(skip);
b.skip_exp(skip);
}
}
}