use std::io::{BufRead, BufReader, Read, Seek};
use crate::Result;
pub trait Enumerable {
fn read<R: BufReaderExt>(&mut self, reader: &mut R) -> Result<()>;
}
pub trait BufReaderExt: BufRead + Seek {
fn read_fixed_string(&mut self, length: usize) -> Result<String> {
let mut buffer = vec![0; length];
self.read_exact(&mut buffer)?;
Ok(if buffer == [0xFF; 4] {
String::new() } else {
String::from_utf8(buffer)?
})
}
fn read_null_terminated_string(&mut self) -> Result<String> {
let mut buffer = Vec::with_capacity(150); self.read_until(0x00, &mut buffer)?;
buffer.pop();
let string = String::from_utf8(buffer)?;
Ok(string)
}
fn read_enumerable<T: Default + Enumerable>(&mut self, count: u64) -> Result<Vec<T>>
where
Self: Sized,
Vec<T>: FromIterator<T>,
{
let mut enumerables = vec![];
enumerables.reserve_exact(usize::try_from(count)? + 1);
for _ in 0..count {
let mut enumerable = T::default();
enumerable.read(self)?;
enumerables.push(enumerable);
}
Ok(enumerables)
}
}
impl<R: Read + Seek> BufReaderExt for BufReader<R> {}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Cursor;
#[test]
fn test_read_fixed_string_empty() {
let data = [255, 255, 255, 255];
let mut reader = BufReader::new(Cursor::new(&data));
let string = reader.read_fixed_string(data.len()).unwrap();
assert_eq!(string, "");
}
}