diff options
Diffstat (limited to 'src/libstd/io/extensions.rs')
| -rw-r--r-- | src/libstd/io/extensions.rs | 491 |
1 files changed, 491 insertions, 0 deletions
diff --git a/src/libstd/io/extensions.rs b/src/libstd/io/extensions.rs new file mode 100644 index 00000000000..ebda2618dcf --- /dev/null +++ b/src/libstd/io/extensions.rs @@ -0,0 +1,491 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Utility mixins that apply to all Readers and Writers + +// XXX: Not sure how this should be structured +// XXX: Iteration should probably be considered separately + +use iter::Iterator; +use option::Option; +use io::{Reader, Decorator}; + +/// An iterator that reads a single byte on each iteration, +/// until `.read_byte()` returns `None`. +/// +/// # Notes about the Iteration Protocol +/// +/// The `ByteIterator` may yield `None` and thus terminate +/// an iteration, but continue to yield elements if iteration +/// is attempted again. +/// +/// # Failure +/// +/// Raises the same conditions as the `read` method, for +/// each call to its `.next()` method. +/// Yields `None` if the condition is handled. +pub struct ByteIterator<T> { + priv reader: T, +} + +impl<R: Reader> ByteIterator<R> { + pub fn new(r: R) -> ByteIterator<R> { + ByteIterator { reader: r } + } +} + +impl<R> Decorator<R> for ByteIterator<R> { + fn inner(self) -> R { self.reader } + fn inner_ref<'a>(&'a self) -> &'a R { &self.reader } + fn inner_mut_ref<'a>(&'a mut self) -> &'a mut R { &mut self.reader } +} + +impl<'self, R: Reader> Iterator<u8> for ByteIterator<R> { + #[inline] + fn next(&mut self) -> Option<u8> { + self.reader.read_byte() + } +} + +pub fn u64_to_le_bytes<T>(n: u64, size: uint, + f: &fn(v: &[u8]) -> T) -> T { + assert!(size <= 8u); + match size { + 1u => f(&[n as u8]), + 2u => f(&[n as u8, + (n >> 8) as u8]), + 4u => f(&[n as u8, + (n >> 8) as u8, + (n >> 16) as u8, + (n >> 24) as u8]), + 8u => f(&[n as u8, + (n >> 8) as u8, + (n >> 16) as u8, + (n >> 24) as u8, + (n >> 32) as u8, + (n >> 40) as u8, + (n >> 48) as u8, + (n >> 56) as u8]), + _ => { + + let mut bytes: ~[u8] = ~[]; + let mut i = size; + let mut n = n; + while i > 0u { + bytes.push((n & 255_u64) as u8); + n >>= 8_u64; + i -= 1u; + } + f(bytes) + } + } +} + +pub fn u64_to_be_bytes<T>(n: u64, size: uint, + f: &fn(v: &[u8]) -> T) -> T { + assert!(size <= 8u); + match size { + 1u => f(&[n as u8]), + 2u => f(&[(n >> 8) as u8, + n as u8]), + 4u => f(&[(n >> 24) as u8, + (n >> 16) as u8, + (n >> 8) as u8, + n as u8]), + 8u => f(&[(n >> 56) as u8, + (n >> 48) as u8, + (n >> 40) as u8, + (n >> 32) as u8, + (n >> 24) as u8, + (n >> 16) as u8, + (n >> 8) as u8, + n as u8]), + _ => { + let mut bytes: ~[u8] = ~[]; + let mut i = size; + while i > 0u { + let shift = ((i - 1u) * 8u) as u64; + bytes.push((n >> shift) as u8); + i -= 1u; + } + f(bytes) + } + } +} + +pub fn u64_from_be_bytes(data: &[u8], + start: uint, + size: uint) + -> u64 { + let mut sz = size; + assert!((sz <= 8u)); + let mut val = 0_u64; + let mut pos = start; + while sz > 0u { + sz -= 1u; + val += (data[pos] as u64) << ((sz * 8u) as u64); + pos += 1u; + } + return val; +} + +#[cfg(test)] +mod test { + use option::{None, Option, Some}; + use io::mem::{MemReader, MemWriter}; + use io::{Reader, io_error, placeholder_error}; + use vec::ImmutableVector; + + struct InitialZeroByteReader { + count: int, + } + + impl Reader for InitialZeroByteReader { + fn read(&mut self, buf: &mut [u8]) -> Option<uint> { + if self.count == 0 { + self.count = 1; + Some(0) + } else { + buf[0] = 10; + Some(1) + } + } + fn eof(&mut self) -> bool { + false + } + } + + struct EofReader; + + impl Reader for EofReader { + fn read(&mut self, _: &mut [u8]) -> Option<uint> { + None + } + fn eof(&mut self) -> bool { + false + } + } + + struct ErroringReader; + + impl Reader for ErroringReader { + fn read(&mut self, _: &mut [u8]) -> Option<uint> { + io_error::cond.raise(placeholder_error()); + None + } + fn eof(&mut self) -> bool { + false + } + } + + struct PartialReader { + count: int, + } + + impl Reader for PartialReader { + fn read(&mut self, buf: &mut [u8]) -> Option<uint> { + if self.count == 0 { + self.count = 1; + buf[0] = 10; + buf[1] = 11; + Some(2) + } else { + buf[0] = 12; + buf[1] = 13; + Some(2) + } + } + fn eof(&mut self) -> bool { + false + } + } + + struct ErroringLaterReader { + count: int, + } + + impl Reader for ErroringLaterReader { + fn read(&mut self, buf: &mut [u8]) -> Option<uint> { + if self.count == 0 { + self.count = 1; + buf[0] = 10; + Some(1) + } else { + io_error::cond.raise(placeholder_error()); + None + } + } + fn eof(&mut self) -> bool { + false + } + } + + struct ThreeChunkReader { + count: int, + } + + impl Reader for ThreeChunkReader { + fn read(&mut self, buf: &mut [u8]) -> Option<uint> { + if self.count == 0 { + self.count = 1; + buf[0] = 10; + buf[1] = 11; + Some(2) + } else if self.count == 1 { + self.count = 2; + buf[0] = 12; + buf[1] = 13; + Some(2) + } else { + None + } + } + fn eof(&mut self) -> bool { + false + } + } + + #[test] + fn read_byte() { + let mut reader = MemReader::new(~[10]); + let byte = reader.read_byte(); + assert!(byte == Some(10)); + } + + #[test] + fn read_byte_0_bytes() { + let mut reader = InitialZeroByteReader { + count: 0, + }; + let byte = reader.read_byte(); + assert!(byte == Some(10)); + } + + #[test] + fn read_byte_eof() { + let mut reader = EofReader; + let byte = reader.read_byte(); + assert!(byte == None); + } + + #[test] + fn read_byte_error() { + let mut reader = ErroringReader; + do io_error::cond.trap(|_| { + }).inside { + let byte = reader.read_byte(); + assert!(byte == None); + } + } + + #[test] + fn bytes_0_bytes() { + let reader = InitialZeroByteReader { + count: 0, + }; + let byte = reader.bytes().next(); + assert!(byte == Some(10)); + } + + #[test] + fn bytes_eof() { + let reader = EofReader; + let byte = reader.bytes().next(); + assert!(byte == None); + } + + #[test] + fn bytes_error() { + let reader = ErroringReader; + let mut it = reader.bytes(); + do io_error::cond.trap(|_| ()).inside { + let byte = it.next(); + assert!(byte == None); + } + } + + #[test] + fn read_bytes() { + let mut reader = MemReader::new(~[10, 11, 12, 13]); + let bytes = reader.read_bytes(4); + assert!(bytes == ~[10, 11, 12, 13]); + } + + #[test] + fn read_bytes_partial() { + let mut reader = PartialReader { + count: 0, + }; + let bytes = reader.read_bytes(4); + assert!(bytes == ~[10, 11, 12, 13]); + } + + #[test] + fn read_bytes_eof() { + let mut reader = MemReader::new(~[10, 11]); + do io_error::cond.trap(|_| { + }).inside { + assert!(reader.read_bytes(4) == ~[10, 11]); + } + } + + #[test] + fn push_bytes() { + let mut reader = MemReader::new(~[10, 11, 12, 13]); + let mut buf = ~[8, 9]; + reader.push_bytes(&mut buf, 4); + assert!(buf == ~[8, 9, 10, 11, 12, 13]); + } + + #[test] + fn push_bytes_partial() { + let mut reader = PartialReader { + count: 0, + }; + let mut buf = ~[8, 9]; + reader.push_bytes(&mut buf, 4); + assert!(buf == ~[8, 9, 10, 11, 12, 13]); + } + + #[test] + fn push_bytes_eof() { + let mut reader = MemReader::new(~[10, 11]); + let mut buf = ~[8, 9]; + do io_error::cond.trap(|_| { + }).inside { + reader.push_bytes(&mut buf, 4); + assert!(buf == ~[8, 9, 10, 11]); + } + } + + #[test] + fn push_bytes_error() { + let mut reader = ErroringLaterReader { + count: 0, + }; + let mut buf = ~[8, 9]; + do io_error::cond.trap(|_| { } ).inside { + reader.push_bytes(&mut buf, 4); + } + assert!(buf == ~[8, 9, 10]); + } + + #[test] + #[should_fail] + fn push_bytes_fail_reset_len() { + // push_bytes unsafely sets the vector length. This is testing that + // upon failure the length is reset correctly. + let mut reader = ErroringLaterReader { + count: 0, + }; + let buf = @mut ~[8, 9]; + do (|| { + reader.push_bytes(&mut *buf, 4); + }).finally { + // NB: Using rtassert here to trigger abort on failure since this is a should_fail test + // FIXME: #7049 This fails because buf is still borrowed + //rtassert!(*buf == ~[8, 9, 10]); + } + } + + #[test] + fn read_to_end() { + let mut reader = ThreeChunkReader { + count: 0, + }; + let buf = reader.read_to_end(); + assert!(buf == ~[10, 11, 12, 13]); + } + + #[test] + #[should_fail] + fn read_to_end_error() { + let mut reader = ThreeChunkReader { + count: 0, + }; + let buf = reader.read_to_end(); + assert!(buf == ~[10, 11]); + } + + #[test] + fn test_read_write_le_mem() { + let uints = [0, 1, 2, 42, 10_123, 100_123_456, ::u64::max_value]; + + let mut writer = MemWriter::new(); + for i in uints.iter() { + writer.write_le_u64(*i); + } + + let mut reader = MemReader::new(writer.inner()); + for i in uints.iter() { + assert!(reader.read_le_u64() == *i); + } + } + + + #[test] + fn test_read_write_be() { + let uints = [0, 1, 2, 42, 10_123, 100_123_456, ::u64::max_value]; + + let mut writer = MemWriter::new(); + for i in uints.iter() { + writer.write_be_u64(*i); + } + + let mut reader = MemReader::new(writer.inner()); + for i in uints.iter() { + assert!(reader.read_be_u64() == *i); + } + } + + #[test] + fn test_read_be_int_n() { + let ints = [::i32::min_value, -123456, -42, -5, 0, 1, ::i32::max_value]; + + let mut writer = MemWriter::new(); + for i in ints.iter() { + writer.write_be_i32(*i); + } + + let mut reader = MemReader::new(writer.inner()); + for i in ints.iter() { + // this tests that the sign extension is working + // (comparing the values as i32 would not test this) + assert!(reader.read_be_int_n(4) == *i as i64); + } + } + + #[test] + fn test_read_f32() { + //big-endian floating-point 8.1250 + let buf = ~[0x41, 0x02, 0x00, 0x00]; + + let mut writer = MemWriter::new(); + writer.write(buf); + + let mut reader = MemReader::new(writer.inner()); + let f = reader.read_be_f32(); + assert!(f == 8.1250); + } + + #[test] + fn test_read_write_f32() { + let f:f32 = 8.1250; + + let mut writer = MemWriter::new(); + writer.write_be_f32(f); + writer.write_le_f32(f); + + let mut reader = MemReader::new(writer.inner()); + assert!(reader.read_be_f32() == 8.1250); + assert!(reader.read_le_f32() == 8.1250); + } + +} |
