From 13dd50bf61e1d219f65cf15b8e9d745c6623b4e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Harabie=C5=84?= Date: Tue, 10 Oct 2017 14:48:57 +0200 Subject: [PATCH] Simplify BufStream implementation and use it in write test. --- src/utils.rs | 154 ++++++++++++++++++++++++------------------------- tests/read.rs | 2 - tests/write.rs | 11 ++-- 3 files changed, 79 insertions(+), 88 deletions(-) diff --git a/src/utils.rs b/src/utils.rs index cccbf65..4dec42e 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -13,10 +13,9 @@ const BUF_SIZE: usize = 512; pub struct BufStream { inner: T, buf: [u8; BUF_SIZE], - buf_offset: usize, - buf_len: usize, - dirty: bool, - inner_offset: usize, + len: usize, + pos: usize, + write: bool, } impl BufStream { @@ -24,106 +23,103 @@ impl BufStream { BufStream:: { inner, buf: [0; BUF_SIZE], - buf_offset: 0, - buf_len: 0, - dirty: false, - inner_offset: 0, + pos: 0, + len: 0, + write: false, } } -} - -impl Read for BufStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - 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; - } - 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; - } + + fn flush_buf(&mut self) -> io::Result<()> { + if self.write { + self.inner.write_all(&self.buf[..self.pos])?; + self.pos = 0; } - Ok(num_done) + Ok(()) } -} - -impl BufStream { - 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)))?; - } - self.inner.write(&self.buf[..self.buf_len])?; - self.inner_offset = self.buf_len; - self.dirty = false; + + fn make_reader(&mut self) -> io::Result<()> { + if self.write { + self.flush_buf()?; + self.write = false; + self.len = 0; + self.pos = 0; + } + 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 BufRead for BufStream { + 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 Read for BufStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + // 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 Write for BufStream { fn write(&mut self, buf: &[u8]) -> io::Result { - 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 Seek for BufStream { fn seek(&mut self, pos: io::SeekFrom) -> io::Result { - // 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) } } diff --git a/tests/read.rs b/tests/read.rs index 35977e8..0b378d4 100644 --- a/tests/read.rs +++ b/tests/read.rs @@ -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); } diff --git a/tests/write.rs b/tests/write.rs index 47b2526..f1f84c8 100644 --- a/tests/write.rs +++ b/tests/write.rs @@ -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();