use bytes::{BufMut, BytesMut};
pub(crate) fn delta_time_size(delta_time: u32) -> usize {
let mut size = 0;
let mut value = delta_time;
while value > 0 {
size += 1;
value >>= 7;
}
if size == 0 {
size = 1; }
size
}
pub(crate) trait WriteDeltaTimeExt {
fn write_delta_time(&mut self, delta_time: u32);
}
impl WriteDeltaTimeExt for BytesMut {
fn write_delta_time(&mut self, delta_time: u32) {
let num_bytes = delta_time_size(delta_time);
let value_to_write = delta_time;
for i in (0..num_bytes).rev() {
let mut byte = ((value_to_write >> (i * 7)) & 0x7F) as u8;
if i > 0 {
byte |= 0x80; }
self.put_u8(byte);
}
}
}
pub fn read_delta_time(bytes: &[u8]) -> std::io::Result<(u32, &[u8])> {
let mut value: u32 = 0;
let mut shift: u8 = 0;
for (bytes_read, &byte) in bytes.iter().enumerate() {
value |= ((byte & 0x7F) as u32) << shift;
if byte & 0x80 == 0 {
return Ok((value, &bytes[(bytes_read + 1)..]));
}
shift += 7;
}
Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid delta time encoding"))
}
#[cfg(test)]
mod tests {
use super::*;
fn test_delta_time_rw(delta_time: u32, expected_bytes: &[u8]) {
let mut buffer = BytesMut::with_capacity(10);
buffer.write_delta_time(delta_time);
assert_eq!(buffer.len(), expected_bytes.len());
assert_eq!(buffer, expected_bytes);
}
#[test]
fn test_delta_time_zero() {
test_delta_time_rw(0, &[0x00]);
}
#[test]
fn test_one_byte_delta_time() {
test_delta_time_rw(0x7F, &[0x7F]);
test_delta_time_rw(0x40, &[0x40]); }
#[test]
fn test_two_byte_delta_time() {
test_delta_time_rw(0x80, &[0b1000_0001, 0b0000_0000]);
test_delta_time_rw(0x3FFF, &[0xFF, 0x7F]);
test_delta_time_rw(0x2000, &[0xC0, 0x00]);
}
#[test]
fn test_three_byte_delta_time() {
test_delta_time_rw(0x4000, &[0x81, 0x80, 0x00]);
test_delta_time_rw(0x1FFFFF, &[0xFF, 0xFF, 0x7F]);
test_delta_time_rw(0x100000, &[0xC0, 0x80, 0x00]);
}
#[test]
fn test_four_byte_delta_time() {
test_delta_time_rw(0x200000, &[0x81, 0x80, 0x80, 0x00]);
test_delta_time_rw(0x0FFFFFFF, &[0xFF, 0xFF, 0xFF, 0x7F]);
test_delta_time_rw(0x08000000, &[0xC0, 0x80, 0x80, 0x00]);
}
#[test]
fn test_size_calculation() {
assert_eq!(delta_time_size(0), 1);
assert_eq!(delta_time_size(0x7F), 1);
assert_eq!(delta_time_size(0x80), 2);
assert_eq!(delta_time_size(0x3FFF), 2);
assert_eq!(delta_time_size(0x4000), 3);
assert_eq!(delta_time_size(0x1FFFFF), 3);
assert_eq!(delta_time_size(0x200000), 4);
assert_eq!(delta_time_size(0x0FFFFFFF), 4);
}
}