Simplify BufStream implementation and use it in write test.

This commit is contained in:
Rafał Harabień 2017-10-10 14:48:57 +02:00
parent d8eba51b88
commit 13dd50bf61
3 changed files with 79 additions and 88 deletions

View File

@ -13,10 +13,9 @@ const BUF_SIZE: usize = 512;
pub struct BufStream<T: Read+Write+Seek> {
inner: T,
buf: [u8; BUF_SIZE],
buf_offset: usize,
buf_len: usize,
dirty: bool,
inner_offset: usize,
len: usize,
pos: usize,
write: bool,
}
impl<T: Read+Write+Seek> BufStream<T> {
@ -24,106 +23,103 @@ impl<T: Read+Write+Seek> BufStream<T> {
BufStream::<T> {
inner,
buf: [0; BUF_SIZE],
buf_offset: 0,
buf_len: 0,
dirty: false,
inner_offset: 0,
pos: 0,
len: 0,
write: false,
}
}
}
impl<T: Read+Write+Seek> Read for BufStream<T> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let mut num_done = 0;
let mut num_todo = buf.len();
let mut eof = false;
loop {
let num_ready = cmp::min(num_todo, self.buf_len - self.buf_offset);
buf[num_done..num_done+num_ready].clone_from_slice(&self.buf[self.buf_offset..self.buf_offset+num_ready]);
self.buf_offset += num_ready;
num_done += num_ready;
num_todo -= num_ready;
if eof || num_todo == 0 {
break;
fn flush_buf(&mut self) -> io::Result<()> {
if self.write {
self.inner.write_all(&self.buf[..self.pos])?;
self.pos = 0;
}
if num_todo > BUF_SIZE {
let num_read = self.inner.read(&mut buf[num_done..])?;
num_done += num_read;
num_todo -= num_read;
let num_copy = cmp::min(BUF_SIZE, num_done);
self.buf[..num_copy].clone_from_slice(&buf[num_done - num_copy..]);
self.buf_len = num_copy;
self.buf_offset = num_copy;
self.inner_offset = num_copy;
eof = true;
} else {
if self.inner_offset != self.buf_offset {
self.inner.seek(io::SeekFrom::Current((self.buf_offset - self.inner_offset) as i64))?;
Ok(())
}
self.buf_len = self.inner.read(&mut self.buf)?;
self.buf_offset = 0;
self.inner_offset = self.buf_len;
eof = true;
}
}
Ok(num_done)
}
}
impl<T: Read+Write+Seek> BufStream<T> {
fn write_buf(&mut self) -> io::Result<()> {
if self.dirty {
if self.inner_offset > 0 {
self.inner.seek(io::SeekFrom::Current(-(self.inner_offset as i64)))?;
fn make_reader(&mut self) -> io::Result<()> {
if self.write {
self.flush_buf()?;
self.write = false;
self.len = 0;
self.pos = 0;
}
self.inner.write(&self.buf[..self.buf_len])?;
self.inner_offset = self.buf_len;
self.dirty = false;
Ok(())
}
fn make_writter(&mut self) -> io::Result<()> {
if !self.write {
self.inner.seek(io::SeekFrom::Current(-(self.len as i64 - self.pos as i64)))?;
self.write = true;
self.len = 0;
self.pos = 0;
}
Ok(())
}
}
impl<T: Read+Write+Seek> BufRead for BufStream<T> {
fn fill_buf(&mut self) -> io::Result<&[u8]> {
self.make_reader()?;
if self.pos >= self.len {
self.len = self.inner.read(&mut self.buf)?;
self.pos = 0;
}
Ok(&self.buf[self.pos..self.len])
}
fn consume(&mut self, amt: usize) {
self.pos = cmp::min(self.pos + amt, self.len);
}
}
impl<T: Read+Write+Seek> Read for BufStream<T> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
// Make sure we are in read mode
self.make_reader()?;
// Check if this read is bigger than buffer size
if self.pos == self.len && buf.len() >= BUF_SIZE {
return self.inner.read(buf);
}
let nread = {
let mut rem = self.fill_buf()?;
rem.read(buf)?
};
self.consume(nread);
Ok(nread)
}
}
impl<T: Read+Write+Seek> Write for BufStream<T> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let mut num_done = 0;
let mut num_todo = buf.len();
loop {
let num_ready = cmp::min(num_todo, BUF_SIZE - self.buf_offset);
self.buf[self.buf_offset..self.buf_offset+num_ready].clone_from_slice(&buf[num_done..num_done+num_ready]);
self.buf_offset += num_ready;
self.buf_len = cmp::max(self.buf_len, self.buf_offset);
self.dirty = num_ready > 0;
num_done += num_ready;
num_todo -= num_ready;
if num_todo == 0 {
break;
// Make sure we are in write mode
self.make_writter()?;
if self.pos + buf.len() > BUF_SIZE {
self.flush_buf()?;
if buf.len() >= BUF_SIZE {
return self.inner.write(buf);
}
self.write_buf()?;
self.buf_offset = 0;
self.buf_len = 0;
self.inner_offset = 0;
}
Ok(num_done)
let written = (&mut self.buf[self.pos..]).write(buf)?;
self.pos += written;
Ok(written)
}
fn flush(&mut self) -> io::Result<()> {
self.write_buf()?;
self.flush_buf()?;
self.inner.flush()
}
}
impl<T: Read+Write+Seek> Seek for BufStream<T> {
fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
// FIXME: reuse buffer
self.flush_buf()?;
let new_pos = match pos {
io::SeekFrom::Current(x) => io::SeekFrom::Current(x - self.inner_offset as i64 + self.buf_offset as i64),
io::SeekFrom::Current(x) => io::SeekFrom::Current(x - (self.len as i64 - self.pos as i64)),
_ => pos,
};
self.buf_offset = 0;
self.buf_len = 0;
self.inner_offset = 0;
self.pos = 0;
self.len = 0;
self.inner.seek(new_pos)
}
}

View File

@ -16,8 +16,6 @@ fn call_with_fs(f: &Fn(FileSystem) -> (), filename: &str) {
let file = fs::File::open(filename).unwrap();
let mut buf_file = BufStream::new(file);
let fs = FileSystem::new(&mut buf_file).unwrap();
// let mut file = fs::File::open(filename).unwrap();
// let fs = FileSystem::new(&mut file).unwrap();
f(fs);
}

View File

@ -6,7 +6,7 @@ use std::io;
use std::str;
use fatfs::FileSystem;
// use fatfs::BufStream;
use fatfs::BufStream;
const FAT12_IMG: &str = "fat12.img";
const FAT16_IMG: &str = "fat16.img";
@ -21,12 +21,9 @@ fn call_with_fs(f: &Fn(FileSystem) -> (), filename: &str, test_seq: u32) {
fs::create_dir(TMP_DIR).ok();
fs::copy(&img_path, &tmp_path).unwrap();
{
// TODO: fix BufStream
// let file = fs::OpenOptions::new().read(true).write(true).open(&tmp_path).unwrap();
// let mut buf_file = BufStream::new(file);
// let fs = FileSystem::new(&mut buf_file).unwrap();
let mut file = fs::OpenOptions::new().read(true).write(true).open(&tmp_path).unwrap();
let fs = FileSystem::new(&mut file).unwrap();
let file = fs::OpenOptions::new().read(true).write(true).open(&tmp_path).unwrap();
let mut buf_file = BufStream::new(file);
let fs = FileSystem::new(&mut buf_file).unwrap();
f(fs);
}
fs::remove_file(tmp_path).unwrap();