Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add skip(n: uint) to Read, Seek, File, MemReader and BufferedReader #18137

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/libstd/io/buffered.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,17 @@ impl<R: Reader> Reader for BufferedReader<R> {
self.pos += nread;
Ok(nread)
}

fn skip(&mut self, num_bytes: uint) -> IoResult<uint> {
let bytes_in_buf = self.cap - self.pos;
Ok( if num_bytes <= bytes_in_buf {
self.pos += num_bytes;
num_bytes
} else {
self.pos += bytes_in_buf;
bytes_in_buf + try!( self.inner.skip(num_bytes - bytes_in_buf) )
} )
}
}

/// Wraps a Writer and buffers output to it
Expand Down
6 changes: 6 additions & 0 deletions src/libstd/io/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,12 @@ impl File {
err.update_err("couldn't fstat file",
|e| format!("{}; path={}", e, self.path.display()))
}

/// Call Seek::skip(), not Reader::skip().
#[inline]
pub fn skip(&mut self, num_bytes: uint) -> IoResult<uint> {
Seek::skip(self, num_bytes)
}
}

/// Unlink a file from the underlying filesystem.
Expand Down
6 changes: 6 additions & 0 deletions src/libstd/io/mem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,12 @@ impl MemReader {
/// Unwraps this `MemReader`, returning the underlying buffer
#[inline]
pub fn unwrap(self) -> Vec<u8> { self.buf }

/// Call Seek::skip(), not Reader::skip().
#[inline]
pub fn skip(&mut self, num_bytes: uint) -> IoResult<uint> {
Seek::skip(self, num_bytes)
}
}

impl Reader for MemReader {
Expand Down
104 changes: 90 additions & 14 deletions src/libstd/io/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,20 +228,22 @@ use fmt;
use int;
use iter::Iterator;
use libc;
use mem::transmute;
use mem::{transmute, uninitialized}; // std::mem is shadowed by self::mem
use cmp;
use ops::{BitOr, BitXor, BitAnd, Sub, Not};
use option::{Option, Some, None};
use os;
use boxed::Box;
use result::{Ok, Err, Result};
use rt::rtio;
use slice::{AsSlice, ImmutableSlice};
use slice::{AsSlice, ImmutableSlice, MutableSlice};
use str::{Str, StrSlice};
use str;
use string::String;
use uint;
use unicode::char::UnicodeChar;
use vec::Vec;
use num::ToPrimitive;

// Reexports
pub use self::stdio::stdin;
Expand Down Expand Up @@ -521,7 +523,8 @@ impl<T> UpdateIoError<T> for IoResult<T> {
}
}

static NO_PROGRESS_LIMIT: uint = 1000;
const NO_PROGRESS_LIMIT: uint = 1000;
const SKIP_SIZE: uint = 1 << 10;

/// A trait for objects which are byte-oriented streams. Readers are defined by
/// one method, `read`. This function will block until data is available,
Expand Down Expand Up @@ -940,6 +943,23 @@ pub trait Reader {
fn by_ref<'a>(&'a mut self) -> RefReader<'a, Self> {
RefReader { inner: self }
}

/// Issue the read() method inside but discard the result.
///
/// Return the number of bytes read until it encounters any Err or 0 bytes return.
fn skip(&mut self, num_bytes: uint) -> IoResult<uint> {
let mut remaining = num_bytes;
let mut buf: [u8, .. SKIP_SIZE] = unsafe { uninitialized() };
loop {
let n_bytes_to_read = cmp::max(buf.len(), remaining);
let n_read_bytes = try!( self.read(buf.slice_to_mut(n_bytes_to_read)) );
remaining -= n_read_bytes;
if n_read_bytes == 0 || remaining == 0 {
break;
}
}
Ok(num_bytes - remaining)
}
}

impl<'a> Reader for Box<Reader+'a> {
Expand Down Expand Up @@ -1583,6 +1603,16 @@ pub trait Seek {
/// stream, but the next write may cause the previous data to be filled in
/// with a bit pattern.
fn seek(&mut self, pos: i64, style: SeekStyle) -> IoResult<()>;

/// Wrap seek(num_byes, SeekCur) to provide something similar with Reader::skip().
///
/// # Failure
///
/// Fails when num_bytes doesn't fit into i64.
#[inline]
fn skip(&mut self, num_bytes: uint) -> IoResult<uint> {
self.seek(num_bytes.to_i64().unwrap(), SeekCur).and(Ok(num_bytes))
}
}

/// A listener is a value that can consume itself to start listening for
Expand Down Expand Up @@ -1908,7 +1938,8 @@ impl fmt::Show for FilePermission {

#[cfg(test)]
mod tests {
use super::{IoResult, Reader, MemReader, NoProgress, InvalidInput};
use super::{IoResult, Reader, MemReader, NoProgress, InvalidInput, EndOfFile};
use super::SKIP_SIZE;
use prelude::*;
use uint;

Expand All @@ -1927,6 +1958,10 @@ mod tests {
fn new(r: T, behavior: Vec<BadReaderBehavior>) -> BadReader<T> {
BadReader { behavior: behavior, r: r }
}

fn simply_new(r: T) -> BadReader<T> {
BadReader::new(r, vec![])
}
}

impl<T: Reader> Reader for BadReader<T> {
Expand Down Expand Up @@ -1956,20 +1991,18 @@ mod tests {

#[test]
fn test_read_at_least() {
let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()),
vec![GoodBehavior(uint::MAX)]);
let mut r = BadReader::simply_new(MemReader::new(b"hello, world!".to_vec()));
let mut buf = [0u8, ..5];
assert!(r.read_at_least(1, buf).unwrap() >= 1);
assert!(r.read_exact(5).unwrap().len() == 5); // read_exact uses read_at_least
assert!(r.read_at_least(0, buf).is_ok());

let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()),
vec![BadBehavior(50), GoodBehavior(uint::MAX)]);
vec![BadBehavior(50)]);
assert!(r.read_at_least(1, buf).unwrap() >= 1);

let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()),
vec![BadBehavior(1), GoodBehavior(1),
BadBehavior(50), GoodBehavior(uint::MAX)]);
vec![BadBehavior(1), GoodBehavior(1), BadBehavior(50)]);
assert!(r.read_at_least(1, buf).unwrap() >= 1);
assert!(r.read_at_least(1, buf).unwrap() >= 1);

Expand All @@ -1984,19 +2017,17 @@ mod tests {

#[test]
fn test_push_at_least() {
let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()),
vec![GoodBehavior(uint::MAX)]);
let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()), vec![]);
let mut buf = Vec::new();
assert!(r.push_at_least(1, 5, &mut buf).unwrap() >= 1);
assert!(r.push_at_least(0, 5, &mut buf).is_ok());

let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()),
vec![BadBehavior(50), GoodBehavior(uint::MAX)]);
vec![BadBehavior(50)]);
assert!(r.push_at_least(1, 5, &mut buf).unwrap() >= 1);

let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()),
vec![BadBehavior(1), GoodBehavior(1),
BadBehavior(50), GoodBehavior(uint::MAX)]);
vec![BadBehavior(1), GoodBehavior(1), BadBehavior(50)]);
assert!(r.push_at_least(1, 5, &mut buf).unwrap() >= 1);
assert!(r.push_at_least(1, 5, &mut buf).unwrap() >= 1);

Expand All @@ -2008,6 +2039,51 @@ mod tests {
assert_eq!(r.push_at_least(5, 1, &mut buf).unwrap_err().kind, InvalidInput);
}

#[test]
fn test_reader_skip() {
{
let mut r = BadReader::simply_new(MemReader::new(b"hello, world!".to_vec()));
assert_eq!(7, r.skip(7).unwrap());
let mut buf = [0_u8, .. 10];
assert_eq!(6, r.read(buf).unwrap());
assert_eq!(b"world!".as_slice(), buf.as_slice());
assert_eq!(EndOfFile, r.skip(0).unwrap_err().kind);
}
{
let mut r = BadReader::simply_new(MemReader::new(
Vec::from_fn(SKIP_SIZE + 20, |i| i as u8)));
assert_eq!(10, r.skip(10).unwrap());
assert_eq!(10, r.read_u8().unwrap());
assert_eq!(SKIP_SIZE, r.skip(SKIP_SIZE).unwrap());
assert_eq!((SKIP_SIZE + 11) as u8, r.read_u8().unwrap());
let mut buf = [0_u8, .. 10];
assert_eq!(8, r.read(buf).unwrap());
assert_eq!(EndOfFile, r.read(buf).unwrap_err().kind);
}
{
let mut r = BadReader::simply_new(MemReader::new(
Vec::from_fn(SKIP_SIZE + 20, |i| i as u8)));
assert_eq!(SKIP_SIZE, r.skip(SKIP_SIZE).unwrap());
assert_eq!(SKIP_SIZE as u8, r.read_u8().unwrap());
assert_eq!(10, r.skip(10).unwrap());
assert_eq!((SKIP_SIZE + 11) as u8, r.read_u8().unwrap());
let mut buf = [0_u8, .. 10];
assert_eq!(8, r.read(buf).unwrap());
assert_eq!(EndOfFile, r.read(buf).unwrap_err().kind);
}
{
let mut r = BadReader::simply_new(MemReader::new(
Vec::from_fn(2 * SKIP_SIZE + 20, |i| i as u8)));
assert_eq!(10, r.skip(10).unwrap());
assert_eq!(10, r.read_u8().unwrap());
assert_eq!(2 * SKIP_SIZE, r.skip(2 * SKIP_SIZE).unwrap());
assert_eq!((2 * SKIP_SIZE + 11) as u8, r.read_u8().unwrap());
let mut buf = [0_u8, .. 10];
assert_eq!(8, r.read(buf).unwrap());
assert_eq!(EndOfFile, r.read(buf).unwrap_err().kind);
}
}

#[test]
fn test_show() {
use super::*;
Expand Down