Introduce an io::Buffer trait
This trait is meant to abstract whether a reader is actually implemented with an underlying buffer. For all readers which are implemented as such, we can efficiently implement things like read_char, read_line, read_until, etc. There are two required methods for managing the internal buffer, and otherwise read_line and friends can all become default methods. Closes #10334
This commit is contained in:
@@ -55,8 +55,7 @@ use prelude::*;
|
|||||||
|
|
||||||
use num;
|
use num;
|
||||||
use vec;
|
use vec;
|
||||||
use str;
|
use super::{Stream, Decorator};
|
||||||
use super::{Reader, Writer, Stream, Decorator};
|
|
||||||
|
|
||||||
// libuv recommends 64k buffers to maximize throughput
|
// libuv recommends 64k buffers to maximize throughput
|
||||||
// https://groups.google.com/forum/#!topic/libuv/oQO1HJAIDdA
|
// https://groups.google.com/forum/#!topic/libuv/oQO1HJAIDdA
|
||||||
@@ -93,45 +92,10 @@ impl<R: Reader> BufferedReader<R> {
|
|||||||
pub fn new(inner: R) -> BufferedReader<R> {
|
pub fn new(inner: R) -> BufferedReader<R> {
|
||||||
BufferedReader::with_capacity(DEFAULT_CAPACITY, inner)
|
BufferedReader::with_capacity(DEFAULT_CAPACITY, inner)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Reads the next line of input, interpreted as a sequence of utf-8
|
impl<R: Reader> Buffer for BufferedReader<R> {
|
||||||
/// encoded unicode codepoints. If a newline is encountered, then the
|
fn fill<'a>(&'a mut self) -> &'a [u8] {
|
||||||
/// newline is contained in the returned string.
|
|
||||||
pub fn read_line(&mut self) -> Option<~str> {
|
|
||||||
self.read_until('\n' as u8).map(str::from_utf8_owned)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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) -> Option<~[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 if res.len() == 0 {None} else {Some(res)};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fill_buffer<'a>(&'a mut self) -> &'a [u8] {
|
|
||||||
if self.pos == self.cap {
|
if self.pos == self.cap {
|
||||||
match self.inner.read(self.buf) {
|
match self.inner.read(self.buf) {
|
||||||
Some(cap) => {
|
Some(cap) => {
|
||||||
@@ -143,12 +107,17 @@ impl<R: Reader> BufferedReader<R> {
|
|||||||
}
|
}
|
||||||
return self.buf.slice(self.pos, self.cap);
|
return self.buf.slice(self.pos, self.cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn consume(&mut self, amt: uint) {
|
||||||
|
self.pos += amt;
|
||||||
|
assert!(self.pos <= self.cap);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Reader> Reader for BufferedReader<R> {
|
impl<R: Reader> Reader for BufferedReader<R> {
|
||||||
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
|
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
|
||||||
let nread = {
|
let nread = {
|
||||||
let available = self.fill_buffer();
|
let available = self.fill();
|
||||||
if available.len() == 0 {
|
if available.len() == 0 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@@ -166,17 +135,9 @@ impl<R: Reader> Reader for BufferedReader<R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Reader> Decorator<R> for BufferedReader<R> {
|
impl<R: Reader> Decorator<R> for BufferedReader<R> {
|
||||||
fn inner(self) -> R {
|
fn inner(self) -> R { self.inner }
|
||||||
self.inner
|
fn inner_ref<'a>(&'a self) -> &'a R { &self.inner }
|
||||||
}
|
fn inner_mut_ref<'a>(&'a mut self) -> &'a mut R { &mut self.inner }
|
||||||
|
|
||||||
fn inner_ref<'a>(&'a self) -> &'a R {
|
|
||||||
&self.inner
|
|
||||||
}
|
|
||||||
|
|
||||||
fn inner_mut_ref<'a>(&'a mut self) -> &'a mut R {
|
|
||||||
&mut self.inner
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wraps a Writer and buffers output to it
|
/// Wraps a Writer and buffers output to it
|
||||||
@@ -279,13 +240,8 @@ impl<W: Writer> Decorator<W> for LineBufferedWriter<W> {
|
|||||||
struct InternalBufferedWriter<W>(BufferedWriter<W>);
|
struct InternalBufferedWriter<W>(BufferedWriter<W>);
|
||||||
|
|
||||||
impl<W: Reader> Reader for InternalBufferedWriter<W> {
|
impl<W: Reader> Reader for InternalBufferedWriter<W> {
|
||||||
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
|
fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.inner.read(buf) }
|
||||||
self.inner.read(buf)
|
fn eof(&mut self) -> bool { self.inner.eof() }
|
||||||
}
|
|
||||||
|
|
||||||
fn eof(&mut self) -> bool {
|
|
||||||
self.inner.eof()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wraps a Stream and buffers input and output to and from it
|
/// Wraps a Stream and buffers input and output to and from it
|
||||||
@@ -311,35 +267,24 @@ impl<S: Stream> BufferedStream<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Stream> Reader for BufferedStream<S> {
|
impl<S: Stream> Buffer for BufferedStream<S> {
|
||||||
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
|
fn fill<'a>(&'a mut self) -> &'a [u8] { self.inner.fill() }
|
||||||
self.inner.read(buf)
|
fn consume(&mut self, amt: uint) { self.inner.consume(amt) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eof(&mut self) -> bool {
|
impl<S: Stream> Reader for BufferedStream<S> {
|
||||||
self.inner.eof()
|
fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.inner.read(buf) }
|
||||||
}
|
fn eof(&mut self) -> bool { self.inner.eof() }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Stream> Writer for BufferedStream<S> {
|
impl<S: Stream> Writer for BufferedStream<S> {
|
||||||
fn write(&mut self, buf: &[u8]) {
|
fn write(&mut self, buf: &[u8]) { self.inner.inner.write(buf) }
|
||||||
self.inner.inner.write(buf)
|
fn flush(&mut self) { self.inner.inner.flush() }
|
||||||
}
|
|
||||||
|
|
||||||
fn flush(&mut self) {
|
|
||||||
self.inner.inner.flush()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: Stream> Decorator<S> for BufferedStream<S> {
|
impl<S: Stream> Decorator<S> for BufferedStream<S> {
|
||||||
fn inner(self) -> S {
|
fn inner(self) -> S { self.inner.inner.inner() }
|
||||||
self.inner.inner.inner()
|
fn inner_ref<'a>(&'a self) -> &'a S { self.inner.inner.inner_ref() }
|
||||||
}
|
|
||||||
|
|
||||||
fn inner_ref<'a>(&'a self) -> &'a S {
|
|
||||||
self.inner.inner.inner_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn inner_mut_ref<'a>(&'a mut self) -> &'a mut S {
|
fn inner_mut_ref<'a>(&'a mut self) -> &'a mut S {
|
||||||
self.inner.inner.inner_mut_ref()
|
self.inner.inner.inner_mut_ref()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,29 +119,18 @@ impl Reader for MemReader {
|
|||||||
|
|
||||||
impl Seek for MemReader {
|
impl Seek for MemReader {
|
||||||
fn tell(&self) -> u64 { self.pos as u64 }
|
fn tell(&self) -> u64 { self.pos as u64 }
|
||||||
|
|
||||||
fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
|
fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Buffer for MemReader {
|
||||||
|
fn fill<'a>(&'a mut self) -> &'a [u8] { self.buf.slice_from(self.pos) }
|
||||||
|
fn consume(&mut self, amt: uint) { self.pos += amt; }
|
||||||
|
}
|
||||||
|
|
||||||
impl Decorator<~[u8]> for MemReader {
|
impl Decorator<~[u8]> for MemReader {
|
||||||
|
fn inner(self) -> ~[u8] { self.buf }
|
||||||
fn inner(self) -> ~[u8] {
|
fn inner_ref<'a>(&'a self) -> &'a ~[u8] { &self.buf }
|
||||||
match self {
|
fn inner_mut_ref<'a>(&'a mut self) -> &'a mut ~[u8] { &mut self.buf }
|
||||||
MemReader { buf: buf, _ } => buf
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn inner_ref<'a>(&'a self) -> &'a ~[u8] {
|
|
||||||
match *self {
|
|
||||||
MemReader { buf: ref buf, _ } => buf
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn inner_mut_ref<'a>(&'a mut self) -> &'a mut ~[u8] {
|
|
||||||
match *self {
|
|
||||||
MemReader { buf: ref mut buf, _ } => buf
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -214,6 +203,11 @@ impl<'self> Seek for BufReader<'self> {
|
|||||||
fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
|
fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'self> Buffer for BufReader<'self> {
|
||||||
|
fn fill<'a>(&'a mut self) -> &'a [u8] { self.buf.slice_from(self.pos) }
|
||||||
|
fn consume(&mut self, amt: uint) { self.pos += amt; }
|
||||||
|
}
|
||||||
|
|
||||||
///Calls a function with a MemWriter and returns
|
///Calls a function with a MemWriter and returns
|
||||||
///the writer's stored vector.
|
///the writer's stored vector.
|
||||||
pub fn with_mem_writer(writeFn:&fn(&mut MemWriter)) -> ~[u8] {
|
pub fn with_mem_writer(writeFn:&fn(&mut MemWriter)) -> ~[u8] {
|
||||||
|
|||||||
@@ -247,11 +247,12 @@ use iter::Iterator;
|
|||||||
use option::{Option, Some, None};
|
use option::{Option, Some, None};
|
||||||
use path::Path;
|
use path::Path;
|
||||||
use result::{Ok, Err, Result};
|
use result::{Ok, Err, Result};
|
||||||
|
use str;
|
||||||
use str::{StrSlice, OwnedStr};
|
use str::{StrSlice, OwnedStr};
|
||||||
use to_str::ToStr;
|
use to_str::ToStr;
|
||||||
use uint;
|
use uint;
|
||||||
use unstable::finally::Finally;
|
use unstable::finally::Finally;
|
||||||
use vec::{OwnedVector, MutableVector};
|
use vec::{OwnedVector, MutableVector, ImmutableVector, OwnedCopyableVector};
|
||||||
use vec;
|
use vec;
|
||||||
|
|
||||||
// Reexports
|
// Reexports
|
||||||
@@ -977,6 +978,78 @@ pub trait Stream: Reader + Writer { }
|
|||||||
|
|
||||||
impl<T: Reader + Writer> Stream for T {}
|
impl<T: Reader + Writer> Stream for T {}
|
||||||
|
|
||||||
|
/// 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
|
||||||
|
/// possible to reasonably implement with purely a read interface.
|
||||||
|
pub trait Buffer: Reader {
|
||||||
|
/// Fills the internal buffer of this object, returning the buffer contents.
|
||||||
|
/// Note that none of the contents will be "read" in the sense that later
|
||||||
|
/// calling `read` may return the same contents.
|
||||||
|
///
|
||||||
|
/// The `consume` function must be called with the number of bytes that are
|
||||||
|
/// consumed from this buffer returned to ensure that the bytes are never
|
||||||
|
/// returned twice.
|
||||||
|
///
|
||||||
|
/// # Failure
|
||||||
|
///
|
||||||
|
/// This function will raise on the `io_error` condition if a read error is
|
||||||
|
/// encountered.
|
||||||
|
fn fill<'a>(&'a mut self) -> &'a [u8];
|
||||||
|
|
||||||
|
/// Tells this buffer that `amt` bytes have been consumed from the buffer,
|
||||||
|
/// so they should no longer be returned in calls to `fill` or `read`.
|
||||||
|
fn consume(&mut self, amt: 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.
|
||||||
|
///
|
||||||
|
/// # 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
|
||||||
|
/// 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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.
|
||||||
|
///
|
||||||
|
/// # Failure
|
||||||
|
///
|
||||||
|
/// This function will raise on the `io_error` condition if a read error is
|
||||||
|
/// encountered.
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if used == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
self.consume(used);
|
||||||
|
}
|
||||||
|
self.consume(used);
|
||||||
|
return if res.len() == 0 {None} else {Some(res)};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub enum SeekStyle {
|
pub enum SeekStyle {
|
||||||
/// Seek from the beginning of the stream
|
/// Seek from the beginning of the stream
|
||||||
SeekSet,
|
SeekSet,
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ pub use num::{Orderable, Signed, Unsigned, Round};
|
|||||||
pub use num::{Primitive, Int, Float, ToStrRadix, ToPrimitive, FromPrimitive};
|
pub use num::{Primitive, Int, Float, ToStrRadix, ToPrimitive, FromPrimitive};
|
||||||
pub use path::{GenericPath, Path, PosixPath, WindowsPath};
|
pub use path::{GenericPath, Path, PosixPath, WindowsPath};
|
||||||
pub use ptr::RawPtr;
|
pub use ptr::RawPtr;
|
||||||
pub use io::{Writer, Reader, Seek};
|
pub use io::{Buffer, Writer, Reader, Seek};
|
||||||
pub use send_str::{SendStr, SendStrOwned, SendStrStatic, IntoSendStr};
|
pub use send_str::{SendStr, SendStrOwned, SendStrStatic, IntoSendStr};
|
||||||
pub use str::{Str, StrVector, StrSlice, OwnedStr};
|
pub use str::{Str, StrVector, StrSlice, OwnedStr};
|
||||||
pub use to_bytes::IterBytes;
|
pub use to_bytes::IterBytes;
|
||||||
|
|||||||
Reference in New Issue
Block a user