diff options
| author | bors <bors@rust-lang.org> | 2013-11-13 12:21:28 -0800 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2013-11-13 12:21:28 -0800 |
| commit | a79ed57beb759bf1753d80a801756d82bea7ec10 (patch) | |
| tree | 3983a5b78ef7001978e066fc7ff0c6a0e7495ffd /src/libstd | |
| parent | 314d6f693f9442ab40879b58f34c6d0afb76f447 (diff) | |
| parent | c2c7a2497d2005f92834a2c2d6204cc7db783ec9 (diff) | |
| download | rust-a79ed57beb759bf1753d80a801756d82bea7ec10.tar.gz rust-a79ed57beb759bf1753d80a801756d82bea7ec10.zip | |
auto merge of #10451 : zkamsler/rust/buf_writer, r=alexcrichton
I implemented BufWriter. I realize the use of conditions are on their way out for IO, but it does raise a condition if a write will not fit in the buffer for now. I also replaced the seek code for MemWriter. It was adding the offset as a uint, which is unsound for negative offsets. It only happened to work because unsigned addition performs the same operation with two's complement, and sizeof(uint) <= sizeof(i64) so there was no (lack of) sign extension. I replaced this with computing an offset as an i64 and clamping to zero. I don't expect anyone will have use BufWriter with a byte buffer greater than 2^63 bytes any time soon. @alexcrichton Closes #10433
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/io/mem.rs | 109 |
1 files changed, 99 insertions, 10 deletions
diff --git a/src/libstd/io/mem.rs b/src/libstd/io/mem.rs index e754d9be85e..73f38771ada 100644 --- a/src/libstd/io/mem.rs +++ b/src/libstd/io/mem.rs @@ -14,7 +14,7 @@ //! //! * Should probably have something like this for strings. //! * Should they implement Closable? Would take extra state. - +use cmp::max; use cmp::min; use prelude::*; use super::*; @@ -64,15 +64,19 @@ impl Writer for MemWriter { } } +// FIXME(#10432) impl Seek for MemWriter { fn tell(&self) -> u64 { self.pos as u64 } fn seek(&mut self, pos: i64, style: SeekStyle) { - match style { - SeekSet => { self.pos = pos as uint; } - SeekEnd => { self.pos = self.buf.len() + pos as uint; } - SeekCur => { self.pos += pos as uint; } - } + // compute offset as signed and clamp to prevent overflow + let offset = match style { + SeekSet => { 0 } + SeekEnd => { self.buf.len() } + SeekCur => { self.pos } + } as i64; + + self.pos = max(0, offset+pos) as uint; } } @@ -146,6 +150,9 @@ impl Decorator<~[u8]> for MemReader { /// Writes to a fixed-size byte slice +/// +/// If a write will not fit in the buffer, it raises the `io_error` +/// condition and does not write any data. pub struct BufWriter<'self> { priv buf: &'self mut [u8], priv pos: uint @@ -161,15 +168,38 @@ impl<'self> BufWriter<'self> { } impl<'self> Writer for BufWriter<'self> { - fn write(&mut self, _buf: &[u8]) { fail!() } + fn write(&mut self, buf: &[u8]) { + // raises a condition if the entire write does not fit in the buffer + let max_size = self.buf.len(); + if self.pos >= max_size || (self.pos + buf.len()) > max_size { + io_error::cond.raise(IoError { + kind: OtherIoError, + desc: "Trying to write past end of buffer", + detail: None + }); + return; + } - fn flush(&mut self) { fail!() } + vec::bytes::copy_memory(self.buf.mut_slice_from(self.pos), + buf, buf.len()); + self.pos += buf.len(); + } } +// FIXME(#10432) impl<'self> Seek for BufWriter<'self> { - fn tell(&self) -> u64 { fail!() } + fn tell(&self) -> u64 { self.pos as u64 } - fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } + fn seek(&mut self, pos: i64, style: SeekStyle) { + // compute offset as signed and clamp to prevent overflow + let offset = match style { + SeekSet => { 0 } + SeekEnd => { self.buf.len() } + SeekCur => { self.pos } + } as i64; + + self.pos = max(0, offset+pos) as uint; + } } @@ -258,6 +288,65 @@ mod test { } #[test] + fn test_buf_writer() { + let mut buf = [0 as u8, ..8]; + { + let mut writer = BufWriter::new(buf); + assert_eq!(writer.tell(), 0); + writer.write([0]); + assert_eq!(writer.tell(), 1); + writer.write([1, 2, 3]); + writer.write([4, 5, 6, 7]); + assert_eq!(writer.tell(), 8); + } + assert_eq!(buf, [0, 1, 2, 3, 4, 5, 6, 7]); + } + + #[test] + fn test_buf_writer_seek() { + let mut buf = [0 as u8, ..8]; + { + let mut writer = BufWriter::new(buf); + assert_eq!(writer.tell(), 0); + writer.write([1]); + assert_eq!(writer.tell(), 1); + + writer.seek(2, SeekSet); + assert_eq!(writer.tell(), 2); + writer.write([2]); + assert_eq!(writer.tell(), 3); + + writer.seek(-2, SeekCur); + assert_eq!(writer.tell(), 1); + writer.write([3]); + assert_eq!(writer.tell(), 2); + + writer.seek(-1, SeekEnd); + assert_eq!(writer.tell(), 7); + writer.write([4]); + assert_eq!(writer.tell(), 8); + + } + assert_eq!(buf, [1, 3, 2, 0, 0, 0, 0, 4]); + } + + #[test] + fn test_buf_writer_error() { + let mut buf = [0 as u8, ..2]; + let mut writer = BufWriter::new(buf); + writer.write([0]); + + let mut called = false; + do io_error::cond.trap(|err| { + assert_eq!(err.kind, OtherIoError); + called = true; + }).inside { + writer.write([0, 0]); + } + assert!(called); + } + + #[test] fn test_mem_reader() { let mut reader = MemReader::new(~[0, 1, 2, 3, 4, 5, 6, 7]); let mut buf = []; |
