Created
January 22, 2015 23:50
-
-
Save anonymous/4f28bfe06a78b914521a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![allow(unstable)] | |
use std::io; | |
use std::iter::repeat; | |
use std::slice; | |
pub struct Cursor<T> { | |
pos: u64, | |
inner: T, | |
} | |
impl<T> Cursor<T> { | |
pub fn new(inner: T) -> Cursor<T> { | |
Cursor { pos: 0, inner: inner } | |
} | |
pub fn into_inner(self) -> T { self.inner } | |
pub fn get_ref(&self) -> &T { &self.inner } | |
} | |
macro_rules! seek { | |
() => { | |
fn tell(&self) -> io::IoResult<u64> { Ok(self.pos) } | |
fn seek(&mut self, offset: i64, style: io::SeekStyle) -> io::IoResult<()> { | |
let pos = match style { | |
io::SeekSet => 0, | |
io::SeekEnd => self.inner.len() as u64, | |
io::SeekCur => self.pos, | |
} as i64; | |
if offset + pos < 0 { | |
Err(io::IoError { | |
kind: io::InvalidInput, | |
desc: "invalid seek to a negative offset", | |
detail: None | |
}) | |
} else { | |
self.pos = (offset + pos) as u64; | |
Ok(()) | |
} | |
} | |
} | |
} | |
impl io::Seek for Cursor<Vec<u8>> { seek!(); } | |
impl<'a> io::Seek for Cursor<&'a [u8]> { seek!(); } | |
impl<'a> io::Seek for Cursor<&'a mut [u8]> { seek!(); } | |
macro_rules! read { | |
() => { | |
fn read(&mut self, buf: &mut [u8]) -> io::IoResult<usize> { | |
if self.pos > self.inner.len() as u64 { | |
return Err(io::standard_error(io::EndOfFile)) | |
} | |
let mut slice = &self.inner[(self.pos as usize)..]; | |
match slice.read(buf) { | |
Ok(amt) => { | |
self.pos += amt as u64; | |
Ok(amt) | |
} | |
Err(e) => Err(e) | |
} | |
} | |
} | |
} | |
impl io::Reader for Cursor<Vec<u8>> { read!(); } | |
impl<'a> io::Reader for Cursor<&'a [u8]> { read!(); } | |
impl<'a> io::Reader for Cursor<&'a mut [u8]> { read!(); } | |
macro_rules! buffer { | |
() => { | |
fn fill_buf(&mut self) -> io::IoResult<&[u8]> { | |
if self.pos < (self.inner.len() as u64) { | |
Ok(&self.inner[(self.pos as usize)..]) | |
} else { | |
Err(io::standard_error(io::EndOfFile)) | |
} | |
} | |
fn consume(&mut self, amt: usize) { self.pos += amt as u64; } | |
} | |
} | |
impl io::Buffer for Cursor<Vec<u8>> { buffer!(); } | |
impl<'a> io::Buffer for Cursor<&'a [u8]> { buffer!(); } | |
impl<'a> io::Buffer for Cursor<&'a mut [u8]> { buffer!(); } | |
macro_rules! write { | |
() => { | |
} | |
} | |
impl io::Writer for Cursor<Vec<u8>> { | |
fn write(&mut self, buf: &[u8]) -> io::IoResult<()> { | |
if self.pos == self.inner.len() as u64 { | |
self.inner.push_all(buf) | |
} else { | |
// Make sure the internal buffer is as least as big as where we | |
// currently are | |
let difference = self.pos as i64 - self.inner.len() as i64; | |
if difference > 0 { | |
self.inner.extend(repeat(0).take(difference as usize)); | |
} | |
// Figure out what bytes will be used to overwrite what's currently | |
// there (left), and what will be appended on the end (right) | |
let cap = self.inner.len() - (self.pos as usize); | |
let (left, right) = if cap <= buf.len() { | |
(&buf[..cap], &buf[cap..]) | |
} else { | |
let result: (_, &[_]) = (buf, &[]); | |
result | |
}; | |
// Do the necessary writes | |
if left.len() > 0 { | |
let dst = &mut self.inner[(self.pos as usize)..]; | |
slice::bytes::copy_memory(dst, left); | |
} | |
if right.len() > 0 { | |
self.inner.push_all(right); | |
} | |
} | |
// Bump us forward | |
self.pos += buf.len() as u64; | |
Ok(()) | |
} | |
} | |
impl<'a> io::Writer for Cursor<&'a mut [u8]> { | |
fn write(&mut self, data: &[u8]) -> io::IoResult<()> { | |
if self.pos > self.inner.len() as u64 { | |
return Err(io::standard_error(io::EndOfFile)); | |
} | |
let dst = &mut self.inner[(self.pos as usize)..]; | |
let dst_len = dst.len(); | |
if dst_len == 0 { | |
return Err(io::standard_error(io::EndOfFile)); | |
} | |
let src_len = data.len(); | |
if dst_len >= src_len { | |
slice::bytes::copy_memory(dst, data); | |
self.pos += src_len as u64; | |
Ok(()) | |
} else { | |
slice::bytes::copy_memory(dst, &data[..dst_len]); | |
self.pos += dst_len as u64; | |
Err(io::standard_error(io::ShortWrite(dst_len))) | |
} | |
} | |
} | |
#[cfg(test)] | |
mod test { | |
use std::io::{self, SeekSet, SeekCur, SeekEnd}; | |
use super::Cursor; | |
#[test] | |
fn test_vec_writer() { | |
let mut writer = Vec::new(); | |
writer.write(&[0]).unwrap(); | |
writer.write(&[1, 2, 3]).unwrap(); | |
writer.write(&[4, 5, 6, 7]).unwrap(); | |
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; | |
assert_eq!(writer.as_slice(), b); | |
} | |
#[test] | |
fn test_mem_writer() { | |
let mut writer = Cursor::new(Vec::new()); | |
writer.write(&[0]).unwrap(); | |
writer.write(&[1, 2, 3]).unwrap(); | |
writer.write(&[4, 5, 6, 7]).unwrap(); | |
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; | |
assert_eq!(&writer.get_ref()[], b); | |
} | |
#[test] | |
fn test_buf_writer() { | |
let mut buf = [0 as u8; 9]; | |
{ | |
let mut writer = Cursor::new(&mut buf[]); | |
assert_eq!(writer.tell(), Ok(0)); | |
writer.write(&[0]).unwrap(); | |
assert_eq!(writer.tell(), Ok(1)); | |
writer.write(&[1, 2, 3]).unwrap(); | |
writer.write(&[4, 5, 6, 7]).unwrap(); | |
assert_eq!(writer.tell(), Ok(8)); | |
writer.write(&[]).unwrap(); | |
assert_eq!(writer.tell(), Ok(8)); | |
assert_eq!(writer.write(&[8, 9]).err().unwrap().kind, io::ShortWrite(1)); | |
assert_eq!(writer.write(&[10]).err().unwrap().kind, io::EndOfFile); | |
} | |
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; | |
assert_eq!(buf, b); | |
} | |
#[test] | |
fn test_buf_writer_seek() { | |
let mut buf = [0 as u8; 8]; | |
{ | |
let mut writer = Cursor::new(&mut buf[]); | |
assert_eq!(writer.tell(), Ok(0)); | |
writer.write(&[1]).unwrap(); | |
assert_eq!(writer.tell(), Ok(1)); | |
writer.seek(2, SeekSet).unwrap(); | |
assert_eq!(writer.tell(), Ok(2)); | |
writer.write(&[2]).unwrap(); | |
assert_eq!(writer.tell(), Ok(3)); | |
writer.seek(-2, SeekCur).unwrap(); | |
assert_eq!(writer.tell(), Ok(1)); | |
writer.write(&[3]).unwrap(); | |
assert_eq!(writer.tell(), Ok(2)); | |
writer.seek(-1, SeekEnd).unwrap(); | |
assert_eq!(writer.tell(), Ok(7)); | |
writer.write(&[4]).unwrap(); | |
assert_eq!(writer.tell(), Ok(8)); | |
} | |
let b: &[_] = &[1, 3, 2, 0, 0, 0, 0, 4]; | |
assert_eq!(buf, b); | |
} | |
#[test] | |
fn test_buf_writer_error() { | |
let mut buf = [0 as u8; 2]; | |
let mut writer = Cursor::new(&mut buf[]); | |
writer.write(&[0]).unwrap(); | |
match writer.write(&[0, 0]) { | |
Ok(..) => panic!(), | |
Err(e) => assert_eq!(e.kind, io::ShortWrite(1)), | |
} | |
} | |
#[test] | |
fn test_mem_reader() { | |
let mut reader = Cursor::new(vec!(0u8, 1, 2, 3, 4, 5, 6, 7)); | |
let mut buf = []; | |
assert_eq!(reader.read(&mut buf), Ok(0)); | |
assert_eq!(reader.tell(), Ok(0)); | |
let mut buf = [0]; | |
assert_eq!(reader.read(&mut buf), Ok(1)); | |
assert_eq!(reader.tell(), Ok(1)); | |
let b: &[_] = &[0]; | |
assert_eq!(buf, b); | |
let mut buf = [0; 4]; | |
assert_eq!(reader.read(&mut buf), Ok(4)); | |
assert_eq!(reader.tell(), Ok(5)); | |
let b: &[_] = &[1, 2, 3, 4]; | |
assert_eq!(buf, b); | |
assert_eq!(reader.read(&mut buf), Ok(3)); | |
let b: &[_] = &[5, 6, 7]; | |
assert_eq!(&buf[..3], b); | |
assert!(reader.read(&mut buf).is_err()); | |
let mut reader = Cursor::new(vec!(0u8, 1, 2, 3, 4, 5, 6, 7)); | |
assert_eq!(reader.read_until(3).unwrap(), vec!(0, 1, 2, 3)); | |
assert_eq!(reader.read_until(3).unwrap(), vec!(4, 5, 6, 7)); | |
assert!(reader.read(&mut buf).is_err()); | |
} | |
#[test] | |
fn test_slice_reader() { | |
let in_buf = vec![0u8, 1, 2, 3, 4, 5, 6, 7]; | |
let mut reader = &mut in_buf.as_slice(); | |
let mut buf = []; | |
assert_eq!(reader.read(&mut buf), Ok(0)); | |
let mut buf = [0]; | |
assert_eq!(reader.read(&mut buf), Ok(1)); | |
assert_eq!(reader.len(), 7); | |
let b: &[_] = &[0]; | |
assert_eq!(buf.as_slice(), b); | |
let mut buf = [0; 4]; | |
assert_eq!(reader.read(&mut buf), Ok(4)); | |
assert_eq!(reader.len(), 3); | |
let b: &[_] = &[1, 2, 3, 4]; | |
assert_eq!(buf.as_slice(), b); | |
assert_eq!(reader.read(&mut buf), Ok(3)); | |
let b: &[_] = &[5, 6, 7]; | |
assert_eq!(&buf[..3], b); | |
assert!(reader.read(&mut buf).is_err()); | |
let mut reader = &mut in_buf.as_slice(); | |
assert_eq!(reader.read_until(3).unwrap(), vec!(0, 1, 2, 3)); | |
assert_eq!(reader.read_until(3).unwrap(), vec!(4, 5, 6, 7)); | |
assert!(reader.read(&mut buf).is_err()); | |
} | |
#[test] | |
fn test_buf_reader() { | |
let in_buf = vec![0u8, 1, 2, 3, 4, 5, 6, 7]; | |
let mut reader = Cursor::new(in_buf.as_slice()); | |
let mut buf = []; | |
assert_eq!(reader.read(&mut buf), Ok(0)); | |
assert_eq!(reader.tell(), Ok(0)); | |
let mut buf = [0]; | |
assert_eq!(reader.read(&mut buf), Ok(1)); | |
assert_eq!(reader.tell(), Ok(1)); | |
let b: &[_] = &[0]; | |
assert_eq!(buf, b); | |
let mut buf = [0; 4]; | |
assert_eq!(reader.read(&mut buf), Ok(4)); | |
assert_eq!(reader.tell(), Ok(5)); | |
let b: &[_] = &[1, 2, 3, 4]; | |
assert_eq!(buf, b); | |
assert_eq!(reader.read(&mut buf), Ok(3)); | |
let b: &[_] = &[5, 6, 7]; | |
assert_eq!(&buf[..3], b); | |
assert!(reader.read(&mut buf).is_err()); | |
let mut reader = Cursor::new(in_buf.as_slice()); | |
assert_eq!(reader.read_until(3).unwrap(), vec!(0, 1, 2, 3)); | |
assert_eq!(reader.read_until(3).unwrap(), vec!(4, 5, 6, 7)); | |
assert!(reader.read(&mut buf).is_err()); | |
} | |
#[test] | |
fn test_read_char() { | |
let b = b"Vi\xE1\xBB\x87t"; | |
let mut r = Cursor::new(b); | |
assert_eq!(r.read_char(), Ok('V')); | |
assert_eq!(r.read_char(), Ok('i')); | |
assert_eq!(r.read_char(), Ok('ệ')); | |
assert_eq!(r.read_char(), Ok('t')); | |
assert!(r.read_char().is_err()); | |
} | |
#[test] | |
fn test_read_bad_char() { | |
let b = b"\x80"; | |
let mut r = Cursor::new(b); | |
assert!(r.read_char().is_err()); | |
} | |
#[test] | |
fn test_write_strings() { | |
let mut writer = Cursor::new(Vec::new()); | |
writer.write_str("testing").unwrap(); | |
writer.write_line("testing").unwrap(); | |
writer.write_str("testing").unwrap(); | |
let mut r = Cursor::new(&writer.get_ref()[]); | |
assert_eq!(r.read_to_string().unwrap(), "testingtesting\ntesting"); | |
} | |
#[test] | |
fn test_write_char() { | |
let mut writer = Cursor::new(Vec::new()); | |
writer.write_char('a').unwrap(); | |
writer.write_char('\n').unwrap(); | |
writer.write_char('ệ').unwrap(); | |
let mut r = Cursor::new(&writer.get_ref()[]); | |
assert_eq!(r.read_to_string().unwrap(), "a\nệ"); | |
} | |
#[test] | |
fn test_read_whole_string_bad() { | |
let buf = [0xff_u8]; | |
let mut r = Cursor::new(&buf[]); | |
match r.read_to_string() { | |
Ok(..) => panic!(), | |
Err(..) => {} | |
} | |
} | |
#[test] | |
fn seek_past_end() { | |
let buf = [0xff]; | |
let mut r = Cursor::new(&buf[]); | |
r.seek(10, SeekSet).unwrap(); | |
assert!(r.read(&mut []).is_err()); | |
let mut r = Cursor::new(vec!(10u8)); | |
r.seek(10, SeekSet).unwrap(); | |
assert!(r.read(&mut []).is_err()); | |
let mut buf = [0]; | |
let mut r = Cursor::new(&mut buf[]); | |
r.seek(10, SeekSet).unwrap(); | |
assert!(r.write(&[3]).is_err()); | |
} | |
#[test] | |
fn seek_before_0() { | |
let buf = [0xff_u8]; | |
let mut r = Cursor::new(&buf[]); | |
assert!(r.seek(-1, SeekSet).is_err()); | |
let mut r = Cursor::new(vec!(10u8)); | |
assert!(r.seek(-1, SeekSet).is_err()); | |
let mut buf = [0]; | |
let mut r = Cursor::new(&mut buf[]); | |
assert!(r.seek(-1, SeekSet).is_err()); | |
} | |
#[test] | |
fn io_read_at_least() { | |
let mut r = Cursor::new(vec![1u8, 2, 3, 4, 5, 6, 7, 8]); | |
let mut buf = [0; 3]; | |
assert!(r.read_at_least(buf.len(), &mut buf).is_ok()); | |
let b: &[_] = &[1, 2, 3]; | |
assert_eq!(buf, b); | |
assert!(r.read_at_least(0, buf.slice_to_mut(0)).is_ok()); | |
assert_eq!(buf, b); | |
assert!(r.read_at_least(buf.len(), &mut buf).is_ok()); | |
let b: &[_] = &[4, 5, 6]; | |
assert_eq!(buf, b); | |
assert!(r.read_at_least(buf.len(), &mut buf).is_err()); | |
let b: &[_] = &[7, 8, 6]; | |
assert_eq!(buf, b); | |
} | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::Cursor; | |
use std::io; | |
#[test] | |
fn test_seekable_mem_writer() { | |
let mut writer = Cursor::new(Vec::<u8>::new()); | |
assert_eq!(writer.tell(), Ok(0)); | |
writer.write(&[0]).unwrap(); | |
assert_eq!(writer.tell(), Ok(1)); | |
writer.write(&[1, 2, 3]).unwrap(); | |
writer.write(&[4, 5, 6, 7]).unwrap(); | |
assert_eq!(writer.tell(), Ok(8)); | |
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; | |
assert_eq!(&writer.get_ref()[], b); | |
writer.seek(0, io::SeekSet).unwrap(); | |
assert_eq!(writer.tell(), Ok(0)); | |
writer.write(&[3, 4]).unwrap(); | |
let b: &[_] = &[3, 4, 2, 3, 4, 5, 6, 7]; | |
assert_eq!(&writer.get_ref()[], b); | |
writer.seek(1, io::SeekCur).unwrap(); | |
writer.write(&[0, 1]).unwrap(); | |
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 7]; | |
assert_eq!(&writer.get_ref()[], b); | |
writer.seek(-1, io::SeekEnd).unwrap(); | |
writer.write(&[1, 2]).unwrap(); | |
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2]; | |
assert_eq!(&writer.get_ref()[], b); | |
writer.seek(1, io::SeekEnd).unwrap(); | |
writer.write(&[1]).unwrap(); | |
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1]; | |
assert_eq!(&writer.get_ref()[], b); | |
} | |
#[test] | |
fn seek_past_end() { | |
let mut r = Cursor::new(Vec::new()); | |
r.seek(10, io::SeekSet).unwrap(); | |
assert!(r.write(&[3]).is_ok()); | |
} | |
#[test] | |
fn seek_before_0() { | |
let mut r = Cursor::new(Vec::new()); | |
assert!(r.seek(-1, io::SeekSet).is_err()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment