use std::path::{Path, PathBuf};
use std::io::{Error, Read};
pub const BUFFER_SIZE: usize = 8 * 1024;
pub trait DiskBufferTrait {
fn clear(&mut self);
fn get_ref(&self) -> &[u8];
fn is_empty(&self) -> bool;
}
pub struct DiskBufferReader<IO: Read> {
pub data: [u8; BUFFER_SIZE],
pub capacity: usize,
pub file: IO,
pub path: PathBuf,
}
impl<IO: Read> DiskBufferTrait for DiskBufferReader<IO> {
fn clear(&mut self) { self.capacity = 0; }
fn get_ref(&self) -> &[u8] { &self.data[0..self.capacity] }
fn is_empty(&self) -> bool { self.capacity == 0 }
}
impl<IO: Read> DiskBufferReader<IO> {
pub fn new<P: AsRef<Path>>(path: P, file: IO) -> DiskBufferReader<IO> {
DiskBufferReader {
data: [b'\0'; BUFFER_SIZE],
capacity: 0,
file: file,
path: path.as_ref().to_owned(),
}
}
pub fn buffer(&mut self, bytes_used: usize) -> Result<(), Error> {
if bytes_used == 0 {
self.capacity = self.file.read(&mut self.data)?;
} else {
let bytes_unused = self.capacity - bytes_used;
for (left, right) in (0..bytes_unused).zip(bytes_used + 1..bytes_used + bytes_unused) {
self.data[left] = self.data[right];
}
self.capacity = self.file.read(&mut self.data[bytes_unused-1..])? + bytes_unused - 1;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs::File;
#[test]
fn test_disk_buffer_reader_simple() {
let file = include_bytes!("../../tests/buffer.dat");
let mut disk_buffer_reader = DiskBufferReader::new(Path::new("tests/buffer.dat"),
File::open("tests/buffer.dat").expect("unable to open test data"));
let _ = disk_buffer_reader.buffer(0);
assert_eq!(&file[0..BUFFER_SIZE], &disk_buffer_reader.data[..]);
let _ = disk_buffer_reader.buffer(0);
assert_eq!(&file[BUFFER_SIZE..BUFFER_SIZE*2], &disk_buffer_reader.data[..]);
let _ = disk_buffer_reader.buffer(0);
assert_eq!(&file[BUFFER_SIZE*2..], &disk_buffer_reader.data[..2989]);
}
#[test]
fn test_disk_buffer_reader_byte_shifting() {
let file = include_bytes!("../../tests/buffer.dat");
let mut disk_buffer_reader = DiskBufferReader::new(Path::new("tests/buffer.dat"),
File::open("tests/buffer.dat").expect("unable to open test data"));
let _ = disk_buffer_reader.buffer(0);
assert_eq!(&file[0..BUFFER_SIZE], &disk_buffer_reader.data[..]);
let _ = disk_buffer_reader.buffer(BUFFER_SIZE/2);
assert_eq!(&file[BUFFER_SIZE/2+1..BUFFER_SIZE/2+1+BUFFER_SIZE], &disk_buffer_reader.data[0..BUFFER_SIZE]);
}
}