use std::io::Read;
const VAR_INT_ENCODING_BITS: u8 = 7;
const VAR_INT_CONTINUE_FLAG: u8 = 1 << VAR_INT_ENCODING_BITS;
#[inline]
pub fn read_bytes<R: Read, const N: usize>(stream: &mut R) -> std::io::Result<[u8; N]> {
let mut bytes = [0; N];
stream.read_exact(&mut bytes)?;
Ok(bytes)
}
pub fn read_size_encoding<R: Read>(stream: &mut R) -> std::io::Result<usize> {
let mut value = 0;
let mut length = 0;
loop {
let (byte_value, more_bytes) = read_var_int_byte(stream).unwrap();
value |= (byte_value as usize) << length;
if !more_bytes {
return Ok(value);
}
length += VAR_INT_ENCODING_BITS;
}
}
pub fn read_partial_int<R: Read>(
stream: &mut R,
bytes: u8,
present_bytes: &mut u8,
) -> std::io::Result<usize> {
let mut value: usize = 0;
for byte_index in 0..bytes {
if *present_bytes & 1 != 0 {
let [byte] = read_bytes(stream)?;
value |= (byte as usize) << (byte_index * 8);
}
*present_bytes >>= 1;
}
Ok(value)
}
pub fn read_var_int_byte<R: Read>(stream: &mut R) -> std::io::Result<(u8, bool)> {
let [byte] = read_bytes(stream)?;
let value = byte & !VAR_INT_CONTINUE_FLAG;
let more_bytes = byte & VAR_INT_CONTINUE_FLAG != 0;
Ok((value, more_bytes))
}
#[cfg(test)]
mod tests {
use std::io::Cursor;
use super::{read_bytes, read_partial_int, read_size_encoding, read_var_int_byte};
#[test]
fn test_read_bytes() {
let mut cursor = Cursor::new(vec![1u8, 2, 3]);
let bytes: [u8; 3] = read_bytes(&mut cursor).unwrap();
assert_eq!(bytes, [1, 2, 3]);
}
#[test]
fn test_read_var_int_byte() {
let mut cursor = Cursor::new(vec![0b1000_0001, 0b0000_0010]);
let (v1, more1) = read_var_int_byte(&mut cursor).unwrap();
let (v2, more2) = read_var_int_byte(&mut cursor).unwrap();
assert_eq!(v1, 0b0000_0001);
assert!(more1);
assert_eq!(v2, 0b0000_0010);
assert!(!more2);
}
#[test]
fn test_read_size_encoding() {
let mut cursor = Cursor::new(vec![0b1010_1100, 0b0000_0010]);
let v = read_size_encoding(&mut cursor).unwrap();
assert_eq!(v, 300);
}
#[test]
fn test_read_partial_int() {
let mut present = 0b0000_1111;
let mut cursor = Cursor::new(vec![1u8, 2, 3, 4]);
let v = read_partial_int(&mut cursor, 4, &mut present).unwrap();
assert_eq!(v, 0x0403_0201);
}
}