std::io: Add Buffer.lines(), change .bytes() api
- `Buffer.lines()` returns `LineIterator` which yields line using `.read_line()`. - `Reader.bytes()` now takes `&mut self` instead of `self`. - `Reader.read_until()` swallows `EndOfFile`. This also affects `.read_line()`.
This commit is contained in:
parent
b8b16ae099
commit
5a93d12e01
@ -19,10 +19,7 @@ pub fn load_errors(testfile: &Path) -> ~[ExpectedError] {
|
||||
let mut error_patterns = ~[];
|
||||
let mut rdr = BufferedReader::new(File::open(testfile).unwrap());
|
||||
let mut line_num = 1u;
|
||||
loop {
|
||||
let ln = match rdr.read_line() {
|
||||
Some(ln) => ln, None => break,
|
||||
};
|
||||
for ln in rdr.lines() {
|
||||
error_patterns.push_all_move(parse_expected(line_num, ln));
|
||||
line_num += 1u;
|
||||
}
|
||||
|
@ -107,11 +107,7 @@ fn iter_header(testfile: &Path, it: |&str| -> bool) -> bool {
|
||||
use std::io::File;
|
||||
|
||||
let mut rdr = BufferedReader::new(File::open(testfile).unwrap());
|
||||
loop {
|
||||
let ln = match rdr.read_line() {
|
||||
Some(ln) => ln, None => break
|
||||
};
|
||||
|
||||
for ln in rdr.lines() {
|
||||
// Assume that any directives will be found before the first
|
||||
// module or function. This doesn't seem to be an optimization
|
||||
// with a warm page cache. Maybe with a cold one.
|
||||
|
@ -454,6 +454,28 @@ fn test_line_buffer() {
|
||||
~[0, 1, 0, '\n' as u8, 1, '\n' as u8, 2, 3, '\n' as u8]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_line() {
|
||||
let in_buf = MemReader::new(bytes!("a\nb\nc").to_owned());
|
||||
let mut reader = BufferedReader::with_capacity(2, in_buf);
|
||||
assert_eq!(reader.read_line(), Some(~"a\n"));
|
||||
assert_eq!(reader.read_line(), Some(~"b\n"));
|
||||
assert_eq!(reader.read_line(), Some(~"c"));
|
||||
assert_eq!(reader.read_line(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lines() {
|
||||
let in_buf = MemReader::new(bytes!("a\nb\nc").to_owned());
|
||||
let mut reader = BufferedReader::with_capacity(2, in_buf);
|
||||
let mut it = reader.lines();
|
||||
assert_eq!(it.next(), Some(~"a\n"));
|
||||
assert_eq!(it.next(), Some(~"b\n"));
|
||||
assert_eq!(it.next(), Some(~"c"));
|
||||
assert_eq!(it.next(), None);
|
||||
}
|
||||
|
||||
|
||||
#[bench]
|
||||
fn bench_buffered_reader(bh: &mut Harness) {
|
||||
bh.iter(|| {
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
use iter::Iterator;
|
||||
use option::Option;
|
||||
use io::{Reader, Decorator};
|
||||
use io::Reader;
|
||||
|
||||
/// An iterator that reads a single byte on each iteration,
|
||||
/// until `.read_byte()` returns `None`.
|
||||
@ -31,23 +31,17 @@
|
||||
/// 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,
|
||||
pub struct ByteIterator<'r, T> {
|
||||
priv reader: &'r mut T,
|
||||
}
|
||||
|
||||
impl<R: Reader> ByteIterator<R> {
|
||||
pub fn new(r: R) -> ByteIterator<R> {
|
||||
impl<'r, R: Reader> ByteIterator<'r, R> {
|
||||
pub fn new(r: &'r mut R) -> ByteIterator<'r, 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> {
|
||||
impl<'r, R: Reader> Iterator<u8> for ByteIterator<'r, R> {
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<u8> {
|
||||
self.reader.read_byte()
|
||||
@ -285,7 +279,7 @@ fn read_byte_error() {
|
||||
|
||||
#[test]
|
||||
fn bytes_0_bytes() {
|
||||
let reader = InitialZeroByteReader {
|
||||
let mut reader = InitialZeroByteReader {
|
||||
count: 0,
|
||||
};
|
||||
let byte = reader.bytes().next();
|
||||
@ -294,14 +288,14 @@ fn bytes_0_bytes() {
|
||||
|
||||
#[test]
|
||||
fn bytes_eof() {
|
||||
let reader = EofReader;
|
||||
let mut reader = EofReader;
|
||||
let byte = reader.bytes().next();
|
||||
assert!(byte == None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bytes_error() {
|
||||
let reader = ErroringReader;
|
||||
let mut reader = ErroringReader;
|
||||
let mut it = reader.bytes();
|
||||
io_error::cond.trap(|_| ()).inside(|| {
|
||||
let byte = it.next();
|
||||
|
@ -25,41 +25,63 @@
|
||||
|
||||
* Read lines from stdin
|
||||
|
||||
for stdin().each_line |line| {
|
||||
println(line)
|
||||
```rust
|
||||
let mut stdin = BufferedReader::new(stdin());
|
||||
for line in stdin.lines() {
|
||||
print(line);
|
||||
}
|
||||
```
|
||||
|
||||
* Read a complete file to a string, (converting newlines?)
|
||||
* Read a complete file
|
||||
|
||||
let contents = File::open("message.txt").read_to_str(); // read_to_str??
|
||||
```rust
|
||||
let contents = File::open(&Path::new("message.txt")).read_to_end();
|
||||
```
|
||||
|
||||
* Write a line to a file
|
||||
|
||||
let file = File::open("message.txt", Create, Write);
|
||||
file.write_line("hello, file!");
|
||||
```rust
|
||||
let mut file = File::create(&Path::new("message.txt"));
|
||||
file.write(bytes!("hello, file!\n"));
|
||||
```
|
||||
|
||||
* Iterate over the lines of a file
|
||||
|
||||
File::open("message.txt").each_line(|line| {
|
||||
println(line)
|
||||
})
|
||||
```rust
|
||||
let path = Path::new("message.txt");
|
||||
let mut file = BufferedReader::new(File::open(&path));
|
||||
for line in file.lines() {
|
||||
print(line);
|
||||
}
|
||||
```
|
||||
|
||||
* Pull the lines of a file into a vector of strings
|
||||
|
||||
let lines = File::open("message.txt").lines().to_vec();
|
||||
```rust
|
||||
let path = Path::new("message.txt");
|
||||
let mut file = BufferedReader::new(File::open(&path));
|
||||
let lines: ~[~str] = file.lines().collect();
|
||||
```
|
||||
|
||||
* Make an simple HTTP request
|
||||
XXX This needs more improvement: TcpStream constructor taking &str,
|
||||
`write_str` and `write_line` methods.
|
||||
|
||||
let socket = TcpStream::open("localhost:8080");
|
||||
socket.write_line("GET / HTTP/1.0");
|
||||
socket.write_line("");
|
||||
```rust
|
||||
let addr = from_str::<SocketAddr>("127.0.0.1:8080").unwrap();
|
||||
let mut socket = TcpStream::connect(addr).unwrap();
|
||||
socket.write(bytes!("GET / HTTP/1.0\n\n"));
|
||||
let response = socket.read_to_end();
|
||||
```
|
||||
|
||||
* Connect based on URL? Requires thinking about where the URL type lives
|
||||
and how to make protocol handlers extensible, e.g. the "tcp" protocol
|
||||
yields a `TcpStream`.
|
||||
XXX this is not implemented now.
|
||||
|
||||
connect("tcp://localhost:8080");
|
||||
```rust
|
||||
// connect("tcp://localhost:8080");
|
||||
```
|
||||
|
||||
# Terms
|
||||
|
||||
@ -535,7 +557,8 @@ fn read_bytes(&mut self, len: uint) -> ~[u8] {
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Raises the same conditions as the `read` method.
|
||||
/// Raises the same conditions as the `read` method except for
|
||||
/// `EndOfFile` which is swallowed.
|
||||
fn read_to_end(&mut self) -> ~[u8] {
|
||||
let mut buf = vec::with_capacity(DEFAULT_BUF_SIZE);
|
||||
let mut keep_reading = true;
|
||||
@ -561,7 +584,7 @@ fn read_to_end(&mut self) -> ~[u8] {
|
||||
/// Raises the same conditions as the `read` method, for
|
||||
/// each call to its `.next()` method.
|
||||
/// Ends the iteration if the condition is handled.
|
||||
fn bytes(self) -> extensions::ByteIterator<Self> {
|
||||
fn bytes<'r>(&'r mut self) -> extensions::ByteIterator<'r, Self> {
|
||||
extensions::ByteIterator::new(self)
|
||||
}
|
||||
|
||||
@ -958,6 +981,30 @@ pub trait Stream: Reader + Writer { }
|
||||
|
||||
impl<T: Reader + Writer> Stream for T {}
|
||||
|
||||
/// An iterator that reads a line on each iteration,
|
||||
/// until `.read_line()` returns `None`.
|
||||
///
|
||||
/// # Notes about the Iteration Protocol
|
||||
///
|
||||
/// The `LineIterator` 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 except for `EndOfFile`
|
||||
/// which is swallowed.
|
||||
/// Iteration yields `None` if the condition is handled.
|
||||
struct LineIterator<'r, T> {
|
||||
priv buffer: &'r mut T,
|
||||
}
|
||||
|
||||
impl<'r, T: Buffer> Iterator<~str> for LineIterator<'r, T> {
|
||||
fn next(&mut self) -> Option<~str> {
|
||||
self.buffer.read_line()
|
||||
}
|
||||
}
|
||||
|
||||
/// A Buffer is a type of reader which has some form of internal buffering to
|
||||
/// allow certain kinds of reading operations to be more optimized than others.
|
||||
/// This type extends the `Reader` trait with a few methods that are not
|
||||
@ -987,13 +1034,26 @@ pub trait Buffer: Reader {
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// This function will raise on the `io_error` condition if a read error is
|
||||
/// encountered. The task will also fail if sequence of bytes leading up to
|
||||
/// This function will raise on the `io_error` condition (except for
|
||||
/// `EndOfFile` which is swallowed) if a read error is encountered.
|
||||
/// The task will also fail if sequence of bytes leading up to
|
||||
/// the newline character are not valid utf-8.
|
||||
fn read_line(&mut self) -> Option<~str> {
|
||||
self.read_until('\n' as u8).map(str::from_utf8_owned)
|
||||
}
|
||||
|
||||
/// Create an iterator that reads a line on each iteration until EOF.
|
||||
///
|
||||
/// # Failure
|
||||
///
|
||||
/// Iterator raises the same conditions as the `read` method
|
||||
/// except for `EndOfFile`.
|
||||
fn lines<'r>(&'r mut self) -> LineIterator<'r, Self> {
|
||||
LineIterator {
|
||||
buffer: self,
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads a sequence of bytes leading up to a specified delimeter. Once the
|
||||
/// specified byte is encountered, reading ceases and the bytes up to and
|
||||
/// including the delimiter are returned.
|
||||
@ -1001,32 +1061,40 @@ fn read_line(&mut self) -> Option<~str> {
|
||||
/// # Failure
|
||||
///
|
||||
/// This function will raise on the `io_error` condition if a read error is
|
||||
/// encountered.
|
||||
/// encountered, except that `EndOfFile` is swallowed.
|
||||
fn read_until(&mut self, byte: u8) -> Option<~[u8]> {
|
||||
let mut res = ~[];
|
||||
let mut used;
|
||||
loop {
|
||||
{
|
||||
let available = self.fill();
|
||||
match available.iter().position(|&b| b == byte) {
|
||||
Some(i) => {
|
||||
res.push_all(available.slice_to(i + 1));
|
||||
used = i + 1;
|
||||
break
|
||||
}
|
||||
None => {
|
||||
res.push_all(available);
|
||||
used = available.len();
|
||||
|
||||
io_error::cond.trap(|e| {
|
||||
if e.kind != EndOfFile {
|
||||
io_error::cond.raise(e);
|
||||
}
|
||||
}).inside(|| {
|
||||
let mut used;
|
||||
loop {
|
||||
{
|
||||
let available = self.fill();
|
||||
match available.iter().position(|&b| b == byte) {
|
||||
Some(i) => {
|
||||
res.push_all(available.slice_to(i + 1));
|
||||
used = i + 1;
|
||||
break
|
||||
}
|
||||
None => {
|
||||
res.push_all(available);
|
||||
used = available.len();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if used == 0 {
|
||||
break
|
||||
if used == 0 {
|
||||
break
|
||||
}
|
||||
self.consume(used);
|
||||
}
|
||||
self.consume(used);
|
||||
}
|
||||
self.consume(used);
|
||||
});
|
||||
return if res.len() == 0 {None} else {Some(res)};
|
||||
|
||||
}
|
||||
|
||||
/// Reads the next utf8-encoded character from the underlying stream.
|
||||
|
@ -77,8 +77,7 @@ fn read_line() {
|
||||
|
||||
for _ in range(0, 3) {
|
||||
let mut reader = BufferedReader::new(File::open(&path).unwrap());
|
||||
while !reader.eof() {
|
||||
reader.read_line();
|
||||
for _line in reader.lines() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -188,14 +188,7 @@ fn main() {
|
||||
// reading the sequence of interest
|
||||
let mut proc_mode = false;
|
||||
|
||||
loop {
|
||||
let line = {
|
||||
let _guard = io::ignore_io_error();
|
||||
match rdr.read_line() {
|
||||
Some(ln) => ln,
|
||||
None => break,
|
||||
}
|
||||
};
|
||||
for line in rdr.lines() {
|
||||
let line = line.trim().to_owned();
|
||||
|
||||
if line.len() == 0u { continue; }
|
||||
|
@ -18,7 +18,6 @@
|
||||
use std::io::stdio::StdReader;
|
||||
use std::io::buffered::BufferedReader;
|
||||
use std::os;
|
||||
use std::uint;
|
||||
use std::unstable::intrinsics::cttz16;
|
||||
use std::vec;
|
||||
|
||||
@ -72,10 +71,7 @@ pub fn read(mut reader: BufferedReader<StdReader>) -> Sudoku {
|
||||
assert!(reader.read_line().unwrap() == ~"9,9"); /* assert first line is exactly "9,9" */
|
||||
|
||||
let mut g = vec::from_fn(10u, { |_i| ~[0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8] });
|
||||
loop {
|
||||
let line = match reader.read_line() {
|
||||
Some(ln) => ln, None => break
|
||||
};
|
||||
for line in reader.lines() {
|
||||
let comps: ~[&str] = line.trim().split(',').collect();
|
||||
|
||||
if comps.len() == 3u {
|
||||
|
Loading…
Reference in New Issue
Block a user