#[repr(packed)]
#[derive(Debug, Clone, Copy)]
struct Header {
secs: u32,
micros: u32,
len: u32,
}
impl Header {
fn time(&self) -> std::time::Duration {
std::time::Duration::from_micros(
u64::from(self.secs) * 1_000_000 + u64::from(self.micros),
)
}
fn len(&self) -> usize {
usize::try_from(self.len).unwrap_or_else(|_| {
panic!("this library requires sizeof(usize) to be at least 4")
})
}
}
#[derive(Debug, Default, Clone)]
pub struct Parser {
reading: std::collections::VecDeque<u8>,
read_state: Option<Header>,
offset: Option<std::time::Duration>,
}
impl Parser {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn add_bytes(&mut self, bytes: &[u8]) {
self.reading.extend(bytes.iter());
}
#[allow(clippy::missing_panics_doc)]
pub fn next_frame(&mut self) -> Option<crate::frame::Frame> {
let header = if let Some(header) = &self.read_state {
header
} else {
if self.reading.len() < std::mem::size_of::<Header>() {
return None;
}
let secs1 = self.reading.pop_front().unwrap();
let secs2 = self.reading.pop_front().unwrap();
let secs3 = self.reading.pop_front().unwrap();
let secs4 = self.reading.pop_front().unwrap();
let secs = u32::from_le_bytes([secs1, secs2, secs3, secs4]);
let micros1 = self.reading.pop_front().unwrap();
let micros2 = self.reading.pop_front().unwrap();
let micros3 = self.reading.pop_front().unwrap();
let micros4 = self.reading.pop_front().unwrap();
let micros =
u32::from_le_bytes([micros1, micros2, micros3, micros4]);
let len1 = self.reading.pop_front().unwrap();
let len2 = self.reading.pop_front().unwrap();
let len3 = self.reading.pop_front().unwrap();
let len4 = self.reading.pop_front().unwrap();
let len = u32::from_le_bytes([len1, len2, len3, len4]);
let header = Header { secs, micros, len };
self.read_state = Some(header);
self.read_state.as_ref().unwrap()
};
if self.reading.len() < header.len() {
return None;
}
let mut data = vec![];
for _ in 0..header.len() {
data.push(
self.reading.pop_front().unwrap(),
);
}
let time = header.time();
self.read_state = None;
if self.offset.is_none() {
self.offset = Some(time);
}
Some(crate::frame::Frame { time, data })
}
#[must_use]
pub fn offset(&self) -> Option<std::time::Duration> {
self.offset
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_basic() {
let bytes = vec![
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 64, 226, 1, 0,
10, 0, 0, 0, 27, 91, 50, 74, 102, 111, 111, 98, 97, 114,
];
let mut parser = Parser::new();
for (i, c) in bytes.into_iter().enumerate() {
parser.add_bytes(&[c]);
let expected = match i {
11 => {
let time = std::time::Duration::new(0, 0);
let data = b"".to_vec();
Some(crate::frame::Frame { time, data })
}
33 => {
let time = std::time::Duration::new(38, 123_456_000);
let data = b"\x1b[2Jfoobar".to_vec();
Some(crate::frame::Frame { time, data })
}
_ => None,
};
let got = parser.next_frame();
assert_eq!(got, expected);
}
}
}