use std::io::{self, Read};
use crate::error::PgsError;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Vint {
pub value: u64,
pub width: u8,
}
#[inline]
pub fn read_element_id<R: Read>(reader: &mut R) -> Result<Vint, PgsError> {
let first = read_byte(reader)?;
if first == 0 {
return Err(PgsError::InvalidVint);
}
let width = first.leading_zeros() as u8 + 1;
if width > 4 {
return Err(PgsError::InvalidVint);
}
let mut value = first as u64;
for _ in 1..width {
let b = read_byte(reader)?;
value = (value << 8) | b as u64;
}
Ok(Vint { value, width })
}
#[inline]
pub fn read_element_size<R: Read>(reader: &mut R) -> Result<Vint, PgsError> {
let first = read_byte(reader)?;
if first == 0 {
return Err(PgsError::InvalidVint);
}
let width = first.leading_zeros() as u8 + 1;
if width > 8 {
return Err(PgsError::InvalidVint);
}
let mask = if width < 8 { 0xFFu8 >> width } else { 0u8 };
let mut value = (first & mask) as u64;
for _ in 1..width {
let b = read_byte(reader)?;
value = (value << 8) | b as u64;
}
let max_for_width = (1u64 << (7 * width)) - 1;
if value == max_for_width {
value = u64::MAX;
}
Ok(Vint { value, width })
}
#[inline]
pub fn read_track_number<R: Read>(reader: &mut R) -> Result<Vint, PgsError> {
read_element_size(reader)
}
#[inline]
fn read_byte<R: Read>(reader: &mut R) -> Result<u8, PgsError> {
let mut buf = [0u8; 1];
reader.read_exact(&mut buf).map_err(|e| {
if e.kind() == io::ErrorKind::UnexpectedEof {
PgsError::InvalidVint
} else {
PgsError::Io(e)
}
})?;
Ok(buf[0])
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Cursor;
#[test]
fn test_element_id_1_byte() {
let mut r = Cursor::new([0xA3]);
let v = read_element_id(&mut r).unwrap();
assert_eq!(v.value, 0xA3);
assert_eq!(v.width, 1);
}
#[test]
fn test_element_id_2_byte() {
let mut r = Cursor::new([0x53, 0xAB]);
let v = read_element_id(&mut r).unwrap();
assert_eq!(v.value, 0x53AB);
assert_eq!(v.width, 2);
}
#[test]
fn test_element_id_4_byte() {
let mut r = Cursor::new([0x18, 0x53, 0x80, 0x67]);
let v = read_element_id(&mut r).unwrap();
assert_eq!(v.value, 0x18538067);
assert_eq!(v.width, 4);
}
#[test]
fn test_element_size_1_byte() {
let mut r = Cursor::new([0x85]);
let v = read_element_size(&mut r).unwrap();
assert_eq!(v.value, 5);
assert_eq!(v.width, 1);
}
#[test]
fn test_element_size_2_byte() {
let mut r = Cursor::new([0x40, 0xC8]);
let v = read_element_size(&mut r).unwrap();
assert_eq!(v.value, 200);
assert_eq!(v.width, 2);
}
#[test]
fn test_element_size_unknown() {
let mut r = Cursor::new([0xFF]);
let v = read_element_size(&mut r).unwrap();
assert_eq!(v.value, u64::MAX);
assert_eq!(v.width, 1);
}
#[test]
fn test_track_number() {
let mut r = Cursor::new([0x81]);
let v = read_track_number(&mut r).unwrap();
assert_eq!(v.value, 1);
assert_eq!(v.width, 1);
let mut r = Cursor::new([0x83]);
let v = read_track_number(&mut r).unwrap();
assert_eq!(v.value, 3);
assert_eq!(v.width, 1);
}
#[test]
fn test_vint_zero_is_error() {
let mut r = Cursor::new([0x00]);
assert!(read_element_id(&mut r).is_err());
}
}