Implement BufferedReader.{read_until, read_line}
These two functions will be useful when replacing various other counterparts used by std::io consumers.
This commit is contained in:
parent
facefa7c8d
commit
ee1e6529bd
1 changed files with 65 additions and 7 deletions
|
|
@ -55,6 +55,7 @@ use prelude::*;
|
|||
|
||||
use num;
|
||||
use vec;
|
||||
use str;
|
||||
use super::{Reader, Writer, Stream, Decorator};
|
||||
|
||||
// libuv recommends 64k buffers to maximize throughput
|
||||
|
|
@ -84,23 +85,69 @@ impl<R: Reader> BufferedReader<R> {
|
|||
pub fn new(inner: R) -> BufferedReader<R> {
|
||||
BufferedReader::with_capacity(DEFAULT_CAPACITY, inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Reader> Reader for BufferedReader<R> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
|
||||
/// Reads the next line of input, interpreted as a sequence of utf-8
|
||||
/// encoded unicode codepoints. If a newline is encountered, then the
|
||||
/// newline is contained in the returned string.
|
||||
pub fn read_line(&mut self) -> ~str {
|
||||
str::from_utf8_owned(self.read_until('\n' as u8))
|
||||
}
|
||||
|
||||
/// 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.
|
||||
pub fn read_until(&mut self, byte: u8) -> ~[u8] {
|
||||
let mut res = ~[];
|
||||
let mut used;
|
||||
loop {
|
||||
{
|
||||
let available = self.fill_buffer();
|
||||
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
|
||||
}
|
||||
self.pos += used;
|
||||
}
|
||||
self.pos += used;
|
||||
return res;
|
||||
}
|
||||
|
||||
fn fill_buffer<'a>(&'a mut self) -> &'a [u8] {
|
||||
if self.pos == self.cap {
|
||||
match self.inner.read(self.buf) {
|
||||
Some(cap) => {
|
||||
self.pos = 0;
|
||||
self.cap = cap;
|
||||
}
|
||||
None => return None
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
return self.buf.slice(self.pos, self.cap);
|
||||
}
|
||||
}
|
||||
|
||||
let src = self.buf.slice(self.pos, self.cap);
|
||||
let nread = num::min(src.len(), buf.len());
|
||||
vec::bytes::copy_memory(buf, src, nread);
|
||||
impl<R: Reader> Reader for BufferedReader<R> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
|
||||
let nread = {
|
||||
let available = self.fill_buffer();
|
||||
if available.len() == 0 {
|
||||
return None;
|
||||
}
|
||||
let nread = num::min(available.len(), buf.len());
|
||||
vec::bytes::copy_memory(buf, available, nread);
|
||||
nread
|
||||
};
|
||||
self.pos += nread;
|
||||
Some(nread)
|
||||
}
|
||||
|
|
@ -355,4 +402,15 @@ mod test {
|
|||
stream.write(buf);
|
||||
stream.flush();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_read_until() {
|
||||
let inner = MemReader::new(~[0, 1, 2, 1, 0]);
|
||||
let mut reader = BufferedReader::with_capacity(2, inner);
|
||||
assert_eq!(reader.read_until(0), Some(~[0]));
|
||||
assert_eq!(reader.read_until(2), Some(~[1, 2]));
|
||||
assert_eq!(reader.read_until(1), Some(~[1]));
|
||||
assert_eq!(reader.read_until(8), Some(~[0]));
|
||||
assert_eq!(reader.read_until(9), None);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue