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
use num;
use vec;
-use str;
-use super::{Reader, Writer, Stream, Decorator};
+use super::{Stream, Decorator};
// libuv recommends 64k buffers to maximize throughput
// https://groups.google.com/forum/#!topic/libuv/oQO1HJAIDdA
pub fn new(inner: R) -> BufferedReader<R> {
BufferedReader::with_capacity(DEFAULT_CAPACITY, inner)
}
+}
- /// 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) -> 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] {
+impl<R: Reader> Buffer for BufferedReader<R> {
+ fn fill<'a>(&'a mut self) -> &'a [u8] {
if self.pos == self.cap {
match self.inner.read(self.buf) {
Some(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> {
fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
let nread = {
- let available = self.fill_buffer();
+ let available = self.fill();
if available.len() == 0 {
return None;
}
}
impl<R: Reader> Decorator<R> for BufferedReader<R> {
- fn inner(self) -> R {
- 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(self) -> R { 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
struct InternalBufferedWriter<W>(BufferedWriter<W>);
impl<W: Reader> Reader for InternalBufferedWriter<W> {
- fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
- self.inner.read(buf)
- }
-
- fn eof(&mut self) -> bool {
- self.inner.eof()
- }
+ fn read(&mut self, buf: &mut [u8]) -> Option<uint> { self.inner.read(buf) }
+ fn eof(&mut self) -> bool { self.inner.eof() }
}
/// Wraps a Stream and buffers input and output to and from it
}
}
-impl<S: Stream> Reader for BufferedStream<S> {
- fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
- self.inner.read(buf)
- }
+impl<S: Stream> Buffer for BufferedStream<S> {
+ fn fill<'a>(&'a mut self) -> &'a [u8] { self.inner.fill() }
+ fn consume(&mut self, amt: uint) { self.inner.consume(amt) }
+}
- fn eof(&mut self) -> bool {
- self.inner.eof()
- }
+impl<S: Stream> Reader for BufferedStream<S> {
+ 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> {
- fn write(&mut self, buf: &[u8]) {
- self.inner.inner.write(buf)
- }
-
- fn flush(&mut self) {
- self.inner.inner.flush()
- }
+ fn write(&mut self, buf: &[u8]) { self.inner.inner.write(buf) }
+ fn flush(&mut self) { self.inner.inner.flush() }
}
impl<S: Stream> Decorator<S> for BufferedStream<S> {
- fn inner(self) -> S {
- self.inner.inner.inner()
- }
-
- fn inner_ref<'a>(&'a self) -> &'a S {
- self.inner.inner.inner_ref()
- }
-
+ fn inner(self) -> S { self.inner.inner.inner() }
+ fn inner_ref<'a>(&'a self) -> &'a S { self.inner.inner.inner_ref() }
fn inner_mut_ref<'a>(&'a mut self) -> &'a mut S {
self.inner.inner.inner_mut_ref()
}
impl Seek for MemReader {
fn tell(&self) -> u64 { self.pos as u64 }
-
fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() }
}
-impl Decorator<~[u8]> for MemReader {
-
- fn inner(self) -> ~[u8] {
- match self {
- MemReader { buf: buf, _ } => buf
- }
- }
-
- fn inner_ref<'a>(&'a self) -> &'a ~[u8] {
- match *self {
- MemReader { buf: ref buf, _ } => buf
- }
- }
+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; }
+}
- fn inner_mut_ref<'a>(&'a mut self) -> &'a mut ~[u8] {
- match *self {
- MemReader { buf: ref mut buf, _ } => buf
- }
- }
+impl Decorator<~[u8]> for MemReader {
+ fn inner(self) -> ~[u8] { self.buf }
+ fn inner_ref<'a>(&'a self) -> &'a ~[u8] { &self.buf }
+ fn inner_mut_ref<'a>(&'a mut self) -> &'a mut ~[u8] { &mut self.buf }
}
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
///the writer's stored vector.
pub fn with_mem_writer(writeFn:&fn(&mut MemWriter)) -> ~[u8] {
use option::{Option, Some, None};
use path::Path;
use result::{Ok, Err, Result};
+use str;
use str::{StrSlice, OwnedStr};
use to_str::ToStr;
use uint;
use unstable::finally::Finally;
-use vec::{OwnedVector, MutableVector};
+use vec::{OwnedVector, MutableVector, ImmutableVector, OwnedCopyableVector};
use vec;
// Reexports
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 {
/// Seek from the beginning of the stream
SeekSet,
pub use num::{Primitive, Int, Float, ToStrRadix, ToPrimitive, FromPrimitive};
pub use path::{GenericPath, Path, PosixPath, WindowsPath};
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 str::{Str, StrVector, StrSlice, OwnedStr};
pub use to_bytes::IterBytes;