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> { pub struct BufStream<T: Read+Write+Seek> {
inner: T, inner: T,
buf: [u8; BUF_SIZE], buf: [u8; BUF_SIZE],
buf_offset: usize, len: usize,
buf_len: usize, pos: usize,
dirty: bool, write: bool,
inner_offset: usize,
} }
impl<T: Read+Write+Seek> BufStream<T> { impl<T: Read+Write+Seek> BufStream<T> {
@ -24,106 +23,103 @@ impl<T: Read+Write+Seek> BufStream<T> {
BufStream::<T> { BufStream::<T> {
inner, inner,
buf: [0; BUF_SIZE], buf: [0; BUF_SIZE],
buf_offset: 0, pos: 0,
buf_len: 0, len: 0,
dirty: false, write: false,
inner_offset: 0,
} }
} }
}
fn flush_buf(&mut self) -> io::Result<()> {
impl<T: Read+Write+Seek> Read for BufStream<T> { if self.write {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.inner.write_all(&self.buf[..self.pos])?;
let mut num_done = 0; self.pos = 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;
}
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))?;
}
self.buf_len = self.inner.read(&mut self.buf)?;
self.buf_offset = 0;
self.inner_offset = self.buf_len;
eof = true;
}
} }
Ok(num_done) Ok(())
} }
}
fn make_reader(&mut self) -> io::Result<()> {
impl<T: Read+Write+Seek> BufStream<T> { if self.write {
fn write_buf(&mut self) -> io::Result<()> { self.flush_buf()?;
if self.dirty { self.write = false;
if self.inner_offset > 0 { self.len = 0;
self.inner.seek(io::SeekFrom::Current(-(self.inner_offset as i64)))?; self.pos = 0;
} }
self.inner.write(&self.buf[..self.buf_len])?; Ok(())
self.inner_offset = self.buf_len; }
self.dirty = false;
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(()) 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> { impl<T: Read+Write+Seek> Write for BufStream<T> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let mut num_done = 0; // Make sure we are in write mode
let mut num_todo = buf.len(); self.make_writter()?;
if self.pos + buf.len() > BUF_SIZE {
loop { self.flush_buf()?;
let num_ready = cmp::min(num_todo, BUF_SIZE - self.buf_offset); if buf.len() >= BUF_SIZE {
self.buf[self.buf_offset..self.buf_offset+num_ready].clone_from_slice(&buf[num_done..num_done+num_ready]); return self.inner.write(buf);
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;
} }
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<()> { fn flush(&mut self) -> io::Result<()> {
self.write_buf()?; self.flush_buf()?;
self.inner.flush() self.inner.flush()
} }
} }
impl<T: Read+Write+Seek> Seek for BufStream<T> { impl<T: Read+Write+Seek> Seek for BufStream<T> {
fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> { fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
// FIXME: reuse buffer self.flush_buf()?;
let new_pos = match pos { 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, _ => pos,
}; };
self.buf_offset = 0; self.pos = 0;
self.buf_len = 0; self.len = 0;
self.inner_offset = 0;
self.inner.seek(new_pos) 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 file = fs::File::open(filename).unwrap();
let mut buf_file = BufStream::new(file); let mut buf_file = BufStream::new(file);
let fs = FileSystem::new(&mut buf_file).unwrap(); 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); f(fs);
} }

View File

@ -6,7 +6,7 @@ use std::io;
use std::str; use std::str;
use fatfs::FileSystem; use fatfs::FileSystem;
// use fatfs::BufStream; use fatfs::BufStream;
const FAT12_IMG: &str = "fat12.img"; const FAT12_IMG: &str = "fat12.img";
const FAT16_IMG: &str = "fat16.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::create_dir(TMP_DIR).ok();
fs::copy(&img_path, &tmp_path).unwrap(); fs::copy(&img_path, &tmp_path).unwrap();
{ {
// TODO: fix BufStream let file = fs::OpenOptions::new().read(true).write(true).open(&tmp_path).unwrap();
// let file = fs::OpenOptions::new().read(true).write(true).open(&tmp_path).unwrap(); let mut buf_file = BufStream::new(file);
// let mut buf_file = BufStream::new(file); let fs = FileSystem::new(&mut buf_file).unwrap();
// 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();
f(fs); f(fs);
} }
fs::remove_file(tmp_path).unwrap(); fs::remove_file(tmp_path).unwrap();