diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs new file mode 100644 index 00000000000..2fd6631ecc4 --- /dev/null +++ b/src/libstd/io/buffered.rs @@ -0,0 +1,676 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +// ignore-lexer-test FIXME #15883 + +//! Buffering wrappers for I/O traits + +use prelude::v1::*; +use io::prelude::*; + +use cmp; +use error::Error as StdError; +use error::FromError; +use fmt; +use io::{self, Cursor, DEFAULT_BUF_SIZE, Error, ErrorKind}; +use ptr; + +/// Wraps a `Read` and buffers input from it +/// +/// It can be excessively inefficient to work directly with a `Read` instance. +/// For example, every call to `read` on `TcpStream` results in a system call. +/// A `BufReader` performs large, infrequent reads on the underlying `Read` +/// and maintains an in-memory buffer of the results. +pub struct BufReader { + inner: R, + buf: Cursor>, +} + +impl BufReader { + /// Creates a new `BufReader` with a default buffer capacity + pub fn new(inner: R) -> BufReader { + BufReader::with_capacity(DEFAULT_BUF_SIZE, inner) + } + + /// Creates a new `BufReader` with the specified buffer capacity + pub fn with_capacity(cap: usize, inner: R) -> BufReader { + BufReader { + inner: inner, + buf: Cursor::new(Vec::with_capacity(cap)), + } + } + + /// Gets a reference to the underlying reader. + pub fn get_ref<'a>(&self) -> &R { &self.inner } + + /// Gets a mutable reference to the underlying reader. + /// + /// # Warning + /// + /// It is inadvisable to directly read from the underlying reader. + pub fn get_mut(&mut self) -> &mut R { &mut self.inner } + + /// Unwraps this `BufReader`, returning the underlying reader. + /// + /// Note that any leftover data in the internal buffer is lost. + pub fn into_inner(self) -> R { self.inner } +} + +impl Read for BufReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + // If we don't have any buffered data and we're doing a massive read + // (larger than our internal buffer), bypass our internal buffer + // entirely. + if self.buf.get_ref().len() == self.buf.position() as usize && + buf.len() >= self.buf.get_ref().capacity() { + return self.inner.read(buf); + } + try!(self.fill_buf()); + self.buf.read(buf) + } +} + +impl BufRead for BufReader { + fn fill_buf(&mut self) -> io::Result<&[u8]> { + // If we've reached the end of our internal buffer then we need to fetch + // some more data from the underlying reader. + if self.buf.position() as usize == self.buf.get_ref().len() { + self.buf.set_position(0); + let v = self.buf.get_mut(); + v.truncate(0); + let inner = &mut self.inner; + try!(super::with_end_to_cap(v, |b| inner.read(b))); + } + self.buf.fill_buf() + } + + fn consume(&mut self, amt: uint) { + self.buf.consume(amt) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for BufReader where R: fmt::Debug { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "BufReader {{ reader: {:?}, buffer: {}/{} }}", + self.inner, self.buf.position(), self.buf.get_ref().len()) + } +} + +/// Wraps a Writer and buffers output to it +/// +/// It can be excessively inefficient to work directly with a `Write`. For +/// example, every call to `write` on `TcpStream` results in a system call. A +/// `BufWriter` keeps an in memory buffer of data and writes it to the +/// underlying `Write` in large, infrequent batches. +/// +/// This writer will be flushed when it is dropped. +pub struct BufWriter { + inner: Option, + buf: Vec, +} + +/// An error returned by `into_inner` which indicates whether a flush error +/// happened or not. +#[derive(Debug)] +pub struct IntoInnerError(W, Error); + +impl BufWriter { + /// Creates a new `BufWriter` with a default buffer capacity + pub fn new(inner: W) -> BufWriter { + BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner) + } + + /// Creates a new `BufWriter` with the specified buffer capacity + pub fn with_capacity(cap: usize, inner: W) -> BufWriter { + BufWriter { + inner: Some(inner), + buf: Vec::with_capacity(cap), + } + } + + fn flush_buf(&mut self) -> io::Result<()> { + let mut written = 0; + let len = self.buf.len(); + let mut ret = Ok(()); + while written < len { + match self.inner.as_mut().unwrap().write(&self.buf[written..]) { + Ok(0) => { + ret = Err(Error::new(ErrorKind::WriteZero, + "failed to flush", None)); + break; + } + Ok(n) => written += n, + Err(e) => { ret = Err(e); break } + + } + } + if written > 0 { + // NB: would be better expressed as .remove(0..n) if it existed + unsafe { + ptr::copy_memory(self.buf.as_mut_ptr(), + self.buf.as_ptr().offset(written as isize), + len - written); + } + } + self.buf.truncate(len - written); + ret + } + + /// Gets a reference to the underlying writer. + pub fn get_ref(&self) -> &W { self.inner.as_ref().unwrap() } + + /// Gets a mutable reference to the underlying write. + /// + /// # Warning + /// + /// It is inadvisable to directly read from the underlying writer. + pub fn get_mut(&mut self) -> &mut W { self.inner.as_mut().unwrap() } + + /// Unwraps this `BufWriter`, returning the underlying writer. + /// + /// The buffer is flushed before returning the writer. + pub fn into_inner(mut self) -> Result>> { + match self.flush_buf() { + Err(e) => Err(IntoInnerError(self, e)), + Ok(()) => Ok(self.inner.take().unwrap()) + } + } +} + +impl Write for BufWriter { + fn write(&mut self, buf: &[u8]) -> io::Result { + if self.buf.len() + buf.len() > self.buf.capacity() { + try!(self.flush_buf()); + } + if buf.len() >= self.buf.capacity() { + self.inner.as_mut().unwrap().write(buf) + } else { + let amt = cmp::min(buf.len(), self.buf.capacity()); + Write::write(&mut self.buf, &buf[..amt]) + } + } + fn flush(&mut self) -> io::Result<()> { + self.flush_buf().and_then(|()| self.get_mut().flush()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for BufWriter where W: fmt::Debug { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "BufWriter {{ writer: {:?}, buffer: {}/{} }}", + self.inner.as_ref().unwrap(), self.buf.len(), self.buf.capacity()) + } +} + +#[unsafe_destructor] +impl Drop for BufWriter { + fn drop(&mut self) { + if self.inner.is_some() { + // dtors should not panic, so we ignore a failed flush + let _r = self.flush_buf(); + } + } +} + +impl IntoInnerError { + /// Returns the error which caused the call to `into_inner` to fail. + /// + /// This error was returned when attempting to flush the internal buffer. + pub fn error(&self) -> &Error { &self.1 } + + /// Returns the underlying `BufWriter` instance which generated the error. + /// + /// The returned object can be used to retry a flush or re-inspect the + /// buffer. + pub fn into_inner(self) -> W { self.0 } +} + +impl FromError> for Error { + fn from_error(iie: IntoInnerError) -> Error { iie.1 } +} + +impl StdError for IntoInnerError { + fn description(&self) -> &str { self.error().description() } +} + +impl fmt::Display for IntoInnerError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.error().fmt(f) + } +} + +/// Wraps a Writer and buffers output to it, flushing whenever a newline +/// (`0x0a`, `'\n'`) is detected. +/// +/// This writer will be flushed when it is dropped. +pub struct LineWriter { + inner: BufWriter, +} + +impl LineWriter { + /// Creates a new `LineWriter` + pub fn new(inner: W) -> LineWriter { + // Lines typically aren't that long, don't use a giant buffer + LineWriter { inner: BufWriter::with_capacity(1024, inner) } + } + + /// Gets a reference to the underlying writer. + /// + /// This type does not expose the ability to get a mutable reference to the + /// underlying reader because that could possibly corrupt the buffer. + pub fn get_ref<'a>(&'a self) -> &'a W { self.inner.get_ref() } + + /// Unwraps this `LineWriter`, returning the underlying writer. + /// + /// The internal buffer is flushed before returning the writer. + pub fn into_inner(self) -> Result>> { + self.inner.into_inner().map_err(|IntoInnerError(buf, e)| { + IntoInnerError(LineWriter { inner: buf }, e) + }) + } +} + +impl Write for LineWriter { + fn write(&mut self, buf: &[u8]) -> io::Result { + match buf.rposition_elem(&b'\n') { + Some(i) => { + let n = try!(self.inner.write(&buf[..i + 1])); + if n != i + 1 { return Ok(n) } + try!(self.inner.flush()); + self.inner.write(&buf[i + 1..]).map(|i| n + i) + } + None => self.inner.write(buf), + } + } + + fn flush(&mut self) -> io::Result<()> { self.inner.flush() } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for LineWriter where W: fmt::Debug { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "LineWriter {{ writer: {:?}, buffer: {}/{} }}", + self.inner.inner, self.inner.buf.len(), + self.inner.buf.capacity()) + } +} + +struct InternalBufWriter(BufWriter); + +impl InternalBufWriter { + fn get_mut(&mut self) -> &mut BufWriter { + let InternalBufWriter(ref mut w) = *self; + return w; + } +} + +impl Read for InternalBufWriter { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.get_mut().inner.as_mut().unwrap().read(buf) + } +} + +/// Wraps a Stream and buffers input and output to and from it. +/// +/// It can be excessively inefficient to work directly with a `Stream`. For +/// example, every call to `read` or `write` on `TcpStream` results in a system +/// call. A `BufStream` keeps in memory buffers of data, making large, +/// infrequent calls to `read` and `write` on the underlying `Stream`. +/// +/// The output half will be flushed when this stream is dropped. +pub struct BufStream { + inner: BufReader> +} + +impl BufStream { + /// Creates a new buffered stream with explicitly listed capacities for the + /// reader/writer buffer. + pub fn with_capacities(reader_cap: usize, writer_cap: usize, inner: S) + -> BufStream { + let writer = BufWriter::with_capacity(writer_cap, inner); + let internal_writer = InternalBufWriter(writer); + let reader = BufReader::with_capacity(reader_cap, internal_writer); + BufStream { inner: reader } + } + + /// Creates a new buffered stream with the default reader/writer buffer + /// capacities. + pub fn new(inner: S) -> BufStream { + BufStream::with_capacities(DEFAULT_BUF_SIZE, DEFAULT_BUF_SIZE, inner) + } + + /// Gets a reference to the underlying stream. + pub fn get_ref(&self) -> &S { + let InternalBufWriter(ref w) = self.inner.inner; + w.get_ref() + } + + /// Gets a mutable reference to the underlying stream. + /// + /// # Warning + /// + /// It is inadvisable to read directly from or write directly to the + /// underlying stream. + pub fn get_mut(&mut self) -> &mut S { + let InternalBufWriter(ref mut w) = self.inner.inner; + w.get_mut() + } + + /// Unwraps this `BufStream`, returning the underlying stream. + /// + /// The internal buffer is flushed before returning the stream. Any leftover + /// data in the read buffer is lost. + pub fn into_inner(self) -> Result>> { + let BufReader { inner: InternalBufWriter(w), buf } = self.inner; + w.into_inner().map_err(|IntoInnerError(w, e)| { + IntoInnerError(BufStream { + inner: BufReader { inner: InternalBufWriter(w), buf: buf }, + }, e) + }) + } +} + +impl BufRead for BufStream { + fn fill_buf(&mut self) -> io::Result<&[u8]> { self.inner.fill_buf() } + fn consume(&mut self, amt: uint) { self.inner.consume(amt) } +} + +impl Read for BufStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.inner.read(buf) + } +} + +impl Write for BufStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.inner.inner.get_mut().write(buf) + } + fn flush(&mut self) -> io::Result<()> { + self.inner.inner.get_mut().flush() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for BufStream where S: fmt::Debug { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let reader = &self.inner; + let writer = &self.inner.inner.0; + write!(fmt, "BufStream {{ stream: {:?}, write_buffer: {}/{}, read_buffer: {}/{} }}", + writer.inner, + writer.buf.len(), writer.buf.capacity(), + reader.buf.position(), reader.buf.get_ref().len()) + } +} + +#[cfg(test)] +mod tests { + use prelude::v1::*; + use io::prelude::*; + use io::{self, BufReader, BufWriter, BufStream, Cursor, LineWriter}; + use test; + + /// A dummy reader intended at testing short-reads propagation. + pub struct ShortReader { + lengths: Vec, + } + + impl Read for ShortReader { + fn read(&mut self, _: &mut [u8]) -> io::Result { + if self.lengths.is_empty() { + Ok(0) + } else { + Ok(self.lengths.remove(0)) + } + } + } + + #[test] + fn test_buffered_reader() { + let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; + let mut reader = BufReader::with_capacity(2, inner); + + let mut buf = [0, 0, 0]; + let nread = reader.read(&mut buf); + assert_eq!(Ok(3), nread); + let b: &[_] = &[5, 6, 7]; + assert_eq!(buf, b); + + let mut buf = [0, 0]; + let nread = reader.read(&mut buf); + assert_eq!(Ok(2), nread); + let b: &[_] = &[0, 1]; + assert_eq!(buf, b); + + let mut buf = [0]; + let nread = reader.read(&mut buf); + assert_eq!(Ok(1), nread); + let b: &[_] = &[2]; + assert_eq!(buf, b); + + let mut buf = [0, 0, 0]; + let nread = reader.read(&mut buf); + assert_eq!(Ok(1), nread); + let b: &[_] = &[3, 0, 0]; + assert_eq!(buf, b); + + let nread = reader.read(&mut buf); + assert_eq!(Ok(1), nread); + let b: &[_] = &[4, 0, 0]; + assert_eq!(buf, b); + + assert_eq!(reader.read(&mut buf), Ok(0)); + } + + #[test] + fn test_buffered_writer() { + let inner = Vec::new(); + let mut writer = BufWriter::with_capacity(2, inner); + + writer.write(&[0, 1]).unwrap(); + assert_eq!(*writer.get_ref(), [0, 1]); + + writer.write(&[2]).unwrap(); + assert_eq!(*writer.get_ref(), [0, 1]); + + writer.write(&[3]).unwrap(); + assert_eq!(*writer.get_ref(), [0, 1]); + + writer.flush().unwrap(); + assert_eq!(*writer.get_ref(), [0, 1, 2, 3]); + + writer.write(&[4]).unwrap(); + writer.write(&[5]).unwrap(); + assert_eq!(*writer.get_ref(), [0, 1, 2, 3]); + + writer.write(&[6]).unwrap(); + assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5]); + + writer.write(&[7, 8]).unwrap(); + assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8]); + + writer.write(&[9, 10, 11]).unwrap(); + let a: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; + assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); + + writer.flush().unwrap(); + assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); + } + + #[test] + fn test_buffered_writer_inner_flushes() { + let mut w = BufWriter::with_capacity(3, Vec::new()); + w.write(&[0, 1]).unwrap(); + assert_eq!(*w.get_ref(), []); + let w = w.into_inner().unwrap(); + assert_eq!(w, [0, 1]); + } + + // This is just here to make sure that we don't infinite loop in the + // newtype struct autoderef weirdness + #[test] + fn test_buffered_stream() { + struct S; + + impl Write for S { + fn write(&mut self, b: &[u8]) -> io::Result { Ok(b.len()) } + fn flush(&mut self) -> io::Result<()> { Ok(()) } + } + + impl Read for S { + fn read(&mut self, _: &mut [u8]) -> io::Result { Ok(0) } + } + + let mut stream = BufStream::new(S); + assert_eq!(stream.read(&mut [0; 10]), Ok(0)); + stream.write(&[0; 10]).unwrap(); + stream.flush().unwrap(); + } + + #[test] + fn test_read_until() { + let inner: &[u8] = &[0, 1, 2, 1, 0]; + let mut reader = BufReader::with_capacity(2, inner); + let mut v = Vec::new(); + reader.read_until(0, &mut v).unwrap(); + assert_eq!(v, [0]); + v.truncate(0); + reader.read_until(2, &mut v).unwrap(); + assert_eq!(v, [1, 2]); + v.truncate(0); + reader.read_until(1, &mut v).unwrap(); + assert_eq!(v, [1]); + v.truncate(0); + reader.read_until(8, &mut v).unwrap(); + assert_eq!(v, [0]); + v.truncate(0); + reader.read_until(9, &mut v).unwrap(); + assert_eq!(v, []); + } + + #[test] + fn test_line_buffer() { + let mut writer = LineWriter::new(Vec::new()); + writer.write(&[0]).unwrap(); + assert_eq!(*writer.get_ref(), []); + writer.write(&[1]).unwrap(); + assert_eq!(*writer.get_ref(), []); + writer.flush().unwrap(); + assert_eq!(*writer.get_ref(), [0, 1]); + writer.write(&[0, b'\n', 1, b'\n', 2]).unwrap(); + assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n']); + writer.flush().unwrap(); + assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2]); + writer.write(&[3, b'\n']).unwrap(); + assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2, 3, b'\n']); + } + + #[test] + fn test_read_line() { + let in_buf = b"a\nb\nc"; + let mut reader = BufReader::with_capacity(2, in_buf); + let mut s = String::new(); + reader.read_line(&mut s).unwrap(); + assert_eq!(s, "a\n"); + s.truncate(0); + reader.read_line(&mut s).unwrap(); + assert_eq!(s, "b\n"); + s.truncate(0); + reader.read_line(&mut s).unwrap(); + assert_eq!(s, "c"); + s.truncate(0); + reader.read_line(&mut s).unwrap(); + assert_eq!(s, ""); + } + + #[test] + fn test_lines() { + let in_buf = b"a\nb\nc"; + let mut reader = BufReader::with_capacity(2, in_buf); + let mut it = reader.lines(); + assert_eq!(it.next(), Some(Ok("a".to_string()))); + assert_eq!(it.next(), Some(Ok("b".to_string()))); + assert_eq!(it.next(), Some(Ok("c".to_string()))); + assert_eq!(it.next(), None); + } + + #[test] + fn test_short_reads() { + let inner = ShortReader{lengths: vec![0, 1, 2, 0, 1, 0]}; + let mut reader = BufReader::new(inner); + let mut buf = [0, 0]; + assert_eq!(reader.read(&mut buf), Ok(0)); + assert_eq!(reader.read(&mut buf), Ok(1)); + assert_eq!(reader.read(&mut buf), Ok(2)); + assert_eq!(reader.read(&mut buf), Ok(0)); + assert_eq!(reader.read(&mut buf), Ok(1)); + assert_eq!(reader.read(&mut buf), Ok(0)); + assert_eq!(reader.read(&mut buf), Ok(0)); + } + + #[test] + fn read_char_buffered() { + let buf = [195u8, 159u8]; + let mut reader = BufReader::with_capacity(1, &buf[]); + assert_eq!(reader.chars().next(), Some(Ok('ß'))); + } + + #[test] + fn test_chars() { + let buf = [195u8, 159u8, b'a']; + let mut reader = BufReader::with_capacity(1, &buf[]); + let mut it = reader.chars(); + assert_eq!(it.next(), Some(Ok('ß'))); + assert_eq!(it.next(), Some(Ok('a'))); + assert_eq!(it.next(), None); + } + + #[test] + #[should_fail] + fn dont_panic_in_drop_on_panicked_flush() { + struct FailFlushWriter; + + impl Write for FailFlushWriter { + fn write(&mut self, buf: &[u8]) -> io::Result { Ok(buf.len()) } + fn flush(&mut self) -> io::Result<()> { + Err(io::Error::last_os_error()) + } + } + + let writer = FailFlushWriter; + let _writer = BufWriter::new(writer); + + // If writer panics *again* due to the flush error then the process will + // abort. + panic!(); + } + + #[bench] + fn bench_buffered_reader(b: &mut test::Bencher) { + b.iter(|| { + BufReader::new(io::empty()) + }); + } + + #[bench] + fn bench_buffered_writer(b: &mut test::Bencher) { + b.iter(|| { + BufWriter::new(io::sink()) + }); + } + + #[bench] + fn bench_buffered_stream(b: &mut test::Bencher) { + let mut buf = Cursor::new(Vec::new()); + b.iter(|| { + BufStream::new(&mut buf); + }); + } +} diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs new file mode 100644 index 00000000000..9f3655de20f --- /dev/null +++ b/src/libstd/io/cursor.rs @@ -0,0 +1,408 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(missing_copy_implementations)] + +use prelude::v1::*; +use io::prelude::*; + +use cmp; +use io::{self, SeekFrom, Error, ErrorKind}; +use iter::repeat; +use num::Int; +use slice; + +/// A `Cursor` is a type which wraps another I/O object to provide a `Seek` +/// implementation. +/// +/// Cursors are currently typically used with memory buffer objects in order to +/// allow `Seek` plus `Read` and `Write` implementations. For example, common +/// cursor types include: +/// +/// * `Cursor>` +/// * `Cursor<&[u8]>` +/// +/// Implementations of the I/O traits for `Cursor` are not currently generic +/// over `T` itself. Instead, specific implementations are provided for various +/// in-memory buffer types like `Vec` and `&[u8]`. +pub struct Cursor { + inner: T, + pos: u64, +} + +impl Cursor { + /// Create a new cursor wrapping the provided underlying I/O object. + pub fn new(inner: T) -> Cursor { + Cursor { pos: 0, inner: inner } + } + + /// Consume this cursor, returning the underlying value. + pub fn into_inner(self) -> T { self.inner } + + /// Get a reference to the underlying value in this cursor. + pub fn get_ref(&self) -> &T { &self.inner } + + /// Get a mutable reference to the underlying value in this cursor. + /// + /// Care should be taken to avoid modifying the internal I/O state of the + /// underlying value as it may corrupt this cursor's position. + pub fn get_mut(&mut self) -> &mut T { &mut self.inner } + + /// Returns the current value of this cursor + pub fn position(&self) -> u64 { self.pos } + + /// Sets the value of this cursor + pub fn set_position(&mut self, pos: u64) { self.pos = pos; } +} + +macro_rules! seek { + () => { + fn seek(&mut self, style: SeekFrom) -> io::Result { + let pos = match style { + SeekFrom::Start(n) => { self.pos = n; return Ok(n) } + SeekFrom::End(n) => self.inner.len() as i64 + n, + SeekFrom::Current(n) => self.pos as i64 + n, + }; + + if pos < 0 { + Err(Error::new(ErrorKind::InvalidInput, + "invalid seek to a negative position", + None)) + } else { + self.pos = pos as u64; + Ok(self.pos) + } + } + } +} + +impl<'a> io::Seek for Cursor<&'a [u8]> { seek!(); } +impl<'a> io::Seek for Cursor<&'a mut [u8]> { seek!(); } +impl io::Seek for Cursor> { seek!(); } + +macro_rules! read { + () => { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let n = try!(Read::read(&mut try!(self.fill_buf()), buf)); + self.pos += n as u64; + Ok(n) + } + } +} + +impl<'a> Read for Cursor<&'a [u8]> { read!(); } +impl<'a> Read for Cursor<&'a mut [u8]> { read!(); } +impl Read for Cursor> { read!(); } + +macro_rules! buffer { + () => { + fn fill_buf(&mut self) -> io::Result<&[u8]> { + let amt = cmp::min(self.pos, self.inner.len() as u64); + Ok(&self.inner[(amt as usize)..]) + } + fn consume(&mut self, amt: usize) { self.pos += amt as u64; } + } +} + +impl<'a> BufRead for Cursor<&'a [u8]> { buffer!(); } +impl<'a> BufRead for Cursor<&'a mut [u8]> { buffer!(); } +impl<'a> BufRead for Cursor> { buffer!(); } + +impl<'a> Write for Cursor<&'a mut [u8]> { + fn write(&mut self, data: &[u8]) -> io::Result { + let pos = cmp::min(self.pos, self.inner.len() as u64); + let amt = try!((&mut self.inner[(pos as usize)..]).write(data)); + self.pos += amt as u64; + Ok(amt) + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } +} + +impl Write for Cursor> { + fn write(&mut self, buf: &[u8]) -> io::Result { + // Make sure the internal buffer is as least as big as where we + // currently are + let pos = self.position(); + let amt = pos.saturating_sub(self.inner.len() as u64); + self.inner.extend(repeat(0).take(amt as usize)); + + // Figure out what bytes will be used to overwrite what's currently + // there (left), and what will be appended on the end (right) + let space = self.inner.len() - pos as usize; + let (left, right) = buf.split_at(cmp::min(space, buf.len())); + slice::bytes::copy_memory(&mut self.inner[(pos as usize)..], left); + self.inner.push_all(right); + + // Bump us forward + self.set_position(pos + buf.len() as u64); + Ok(buf.len()) + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } +} + + +#[cfg(test)] +mod tests { + use core::prelude::*; + + use io::prelude::*; + use io::{Cursor, SeekFrom}; + use vec::Vec; + + #[test] + fn test_vec_writer() { + let mut writer = Vec::new(); + assert_eq!(writer.write(&[0]), Ok(1)); + assert_eq!(writer.write(&[1, 2, 3]), Ok(3)); + assert_eq!(writer.write(&[4, 5, 6, 7]), Ok(4)); + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; + assert_eq!(writer, b); + } + + #[test] + fn test_mem_writer() { + let mut writer = Cursor::new(Vec::new()); + assert_eq!(writer.write(&[0]), Ok(1)); + assert_eq!(writer.write(&[1, 2, 3]), Ok(3)); + assert_eq!(writer.write(&[4, 5, 6, 7]), Ok(4)); + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; + assert_eq!(&writer.get_ref()[], b); + } + + #[test] + fn test_buf_writer() { + let mut buf = [0 as u8; 9]; + { + let mut writer = Cursor::new(&mut buf[]); + assert_eq!(writer.position(), 0); + assert_eq!(writer.write(&[0]), Ok(1)); + assert_eq!(writer.position(), 1); + assert_eq!(writer.write(&[1, 2, 3]), Ok(3)); + assert_eq!(writer.write(&[4, 5, 6, 7]), Ok(4)); + assert_eq!(writer.position(), 8); + assert_eq!(writer.write(&[]), Ok(0)); + assert_eq!(writer.position(), 8); + + assert_eq!(writer.write(&[8, 9]), Ok(1)); + assert_eq!(writer.write(&[10]), Ok(0)); + } + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; + assert_eq!(buf, b); + } + + #[test] + fn test_buf_writer_seek() { + let mut buf = [0 as u8; 8]; + { + let mut writer = Cursor::new(&mut buf[]); + assert_eq!(writer.position(), 0); + assert_eq!(writer.write(&[1]), Ok(1)); + assert_eq!(writer.position(), 1); + + assert_eq!(writer.seek(SeekFrom::Start(2)), Ok(2)); + assert_eq!(writer.position(), 2); + assert_eq!(writer.write(&[2]), Ok(1)); + assert_eq!(writer.position(), 3); + + assert_eq!(writer.seek(SeekFrom::Current(-2)), Ok(1)); + assert_eq!(writer.position(), 1); + assert_eq!(writer.write(&[3]), Ok(1)); + assert_eq!(writer.position(), 2); + + assert_eq!(writer.seek(SeekFrom::End(-1)), Ok(7)); + assert_eq!(writer.position(), 7); + assert_eq!(writer.write(&[4]), Ok(1)); + assert_eq!(writer.position(), 8); + + } + let b: &[_] = &[1, 3, 2, 0, 0, 0, 0, 4]; + assert_eq!(buf, b); + } + + #[test] + fn test_buf_writer_error() { + let mut buf = [0 as u8; 2]; + let mut writer = Cursor::new(&mut buf[]); + assert_eq!(writer.write(&[0]), Ok(1)); + assert_eq!(writer.write(&[0, 0]), Ok(1)); + assert_eq!(writer.write(&[0, 0]), Ok(0)); + } + + #[test] + fn test_mem_reader() { + let mut reader = Cursor::new(vec!(0u8, 1, 2, 3, 4, 5, 6, 7)); + let mut buf = []; + assert_eq!(reader.read(&mut buf), Ok(0)); + assert_eq!(reader.position(), 0); + let mut buf = [0]; + assert_eq!(reader.read(&mut buf), Ok(1)); + assert_eq!(reader.position(), 1); + let b: &[_] = &[0]; + assert_eq!(buf, b); + let mut buf = [0; 4]; + assert_eq!(reader.read(&mut buf), Ok(4)); + assert_eq!(reader.position(), 5); + let b: &[_] = &[1, 2, 3, 4]; + assert_eq!(buf, b); + assert_eq!(reader.read(&mut buf), Ok(3)); + let b: &[_] = &[5, 6, 7]; + assert_eq!(&buf[..3], b); + assert_eq!(reader.read(&mut buf), Ok(0)); + } + + #[test] + fn read_to_end() { + let mut reader = Cursor::new(vec!(0u8, 1, 2, 3, 4, 5, 6, 7)); + let mut v = Vec::new(); + reader.read_to_end(&mut v).ok().unwrap(); + assert_eq!(v, [0, 1, 2, 3, 4, 5, 6, 7]); + } + + #[test] + fn test_slice_reader() { + let in_buf = vec![0u8, 1, 2, 3, 4, 5, 6, 7]; + let mut reader = &mut in_buf.as_slice(); + let mut buf = []; + assert_eq!(reader.read(&mut buf), Ok(0)); + let mut buf = [0]; + assert_eq!(reader.read(&mut buf), Ok(1)); + assert_eq!(reader.len(), 7); + let b: &[_] = &[0]; + assert_eq!(buf.as_slice(), b); + let mut buf = [0; 4]; + assert_eq!(reader.read(&mut buf), Ok(4)); + assert_eq!(reader.len(), 3); + let b: &[_] = &[1, 2, 3, 4]; + assert_eq!(buf.as_slice(), b); + assert_eq!(reader.read(&mut buf), Ok(3)); + let b: &[_] = &[5, 6, 7]; + assert_eq!(&buf[..3], b); + assert_eq!(reader.read(&mut buf), Ok(0)); + } + + #[test] + fn test_buf_reader() { + let in_buf = vec![0u8, 1, 2, 3, 4, 5, 6, 7]; + let mut reader = Cursor::new(in_buf.as_slice()); + let mut buf = []; + assert_eq!(reader.read(&mut buf), Ok(0)); + assert_eq!(reader.position(), 0); + let mut buf = [0]; + assert_eq!(reader.read(&mut buf), Ok(1)); + assert_eq!(reader.position(), 1); + let b: &[_] = &[0]; + assert_eq!(buf, b); + let mut buf = [0; 4]; + assert_eq!(reader.read(&mut buf), Ok(4)); + assert_eq!(reader.position(), 5); + let b: &[_] = &[1, 2, 3, 4]; + assert_eq!(buf, b); + assert_eq!(reader.read(&mut buf), Ok(3)); + let b: &[_] = &[5, 6, 7]; + assert_eq!(&buf[..3], b); + assert_eq!(reader.read(&mut buf), Ok(0)); + } + + #[test] + fn test_read_char() { + let b = b"Vi\xE1\xBB\x87t"; + let mut c = Cursor::new(b).chars(); + assert_eq!(c.next(), Some(Ok('V'))); + assert_eq!(c.next(), Some(Ok('i'))); + assert_eq!(c.next(), Some(Ok('ệ'))); + assert_eq!(c.next(), Some(Ok('t'))); + assert_eq!(c.next(), None); + } + + #[test] + fn test_read_bad_char() { + let b = b"\x80"; + let mut c = Cursor::new(b).chars(); + assert!(c.next().unwrap().is_err()); + } + + #[test] + fn seek_past_end() { + let buf = [0xff]; + let mut r = Cursor::new(&buf[]); + assert_eq!(r.seek(SeekFrom::Start(10)), Ok(10)); + assert_eq!(r.read(&mut [0]), Ok(0)); + + let mut r = Cursor::new(vec!(10u8)); + assert_eq!(r.seek(SeekFrom::Start(10)), Ok(10)); + assert_eq!(r.read(&mut [0]), Ok(0)); + + let mut buf = [0]; + let mut r = Cursor::new(&mut buf[]); + assert_eq!(r.seek(SeekFrom::Start(10)), Ok(10)); + assert_eq!(r.write(&[3]), Ok(0)); + } + + #[test] + fn seek_before_0() { + let buf = [0xff_u8]; + let mut r = Cursor::new(&buf[]); + assert!(r.seek(SeekFrom::End(-2)).is_err()); + + let mut r = Cursor::new(vec!(10u8)); + assert!(r.seek(SeekFrom::End(-2)).is_err()); + + let mut buf = [0]; + let mut r = Cursor::new(&mut buf[]); + assert!(r.seek(SeekFrom::End(-2)).is_err()); + } + + #[test] + fn test_seekable_mem_writer() { + let mut writer = Cursor::new(Vec::::new()); + assert_eq!(writer.position(), 0); + assert_eq!(writer.write(&[0]), Ok(1)); + assert_eq!(writer.position(), 1); + assert_eq!(writer.write(&[1, 2, 3]), Ok(3)); + assert_eq!(writer.write(&[4, 5, 6, 7]), Ok(4)); + assert_eq!(writer.position(), 8); + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; + assert_eq!(&writer.get_ref()[], b); + + assert_eq!(writer.seek(SeekFrom::Start(0)), Ok(0)); + assert_eq!(writer.position(), 0); + assert_eq!(writer.write(&[3, 4]), Ok(2)); + let b: &[_] = &[3, 4, 2, 3, 4, 5, 6, 7]; + assert_eq!(&writer.get_ref()[], b); + + assert_eq!(writer.seek(SeekFrom::Current(1)), Ok(3)); + assert_eq!(writer.write(&[0, 1]), Ok(2)); + let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 7]; + assert_eq!(&writer.get_ref()[], b); + + assert_eq!(writer.seek(SeekFrom::End(-1)), Ok(7)); + assert_eq!(writer.write(&[1, 2]), Ok(2)); + let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2]; + assert_eq!(&writer.get_ref()[], b); + + assert_eq!(writer.seek(SeekFrom::End(1)), Ok(10)); + assert_eq!(writer.write(&[1]), Ok(1)); + let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1]; + assert_eq!(&writer.get_ref()[], b); + } + + #[test] + fn vec_seek_past_end() { + let mut r = Cursor::new(Vec::new()); + assert_eq!(r.seek(SeekFrom::Start(10)), Ok(10)); + assert_eq!(r.write(&[3]), Ok(1)); + } + + #[test] + fn vec_seek_before_0() { + let mut r = Cursor::new(Vec::new()); + assert!(r.seek(SeekFrom::End(-2)).is_err()); + } +} diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs new file mode 100644 index 00000000000..9f3cd8c8b15 --- /dev/null +++ b/src/libstd/io/error.rs @@ -0,0 +1,183 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use boxed::Box; +use clone::Clone; +use error::Error as StdError; +use fmt; +use option::Option::{self, Some, None}; +use result; +use string::String; +use sys; + +/// A type for results generated by I/O related functions where the `Err` type +/// is hard-wired to `io::Error`. +/// +/// This typedef is generally used to avoid writing out `io::Error` directly and +/// is otherwise a direct mapping to `std::result::Result`. +pub type Result = result::Result; + +/// The error type for I/O operations of the `Read`, `Write`, `Seek`, and +/// associated traits. +/// +/// Errors mostly originate from the underlying OS, but custom instances of +/// `Error` can be created with crafted error messages and a particular value of +/// `ErrorKind`. +#[derive(PartialEq, Eq, Clone, Debug)] +pub struct Error { + repr: Repr, +} + +#[derive(PartialEq, Eq, Clone, Debug)] +enum Repr { + Os(i32), + Custom(Box), +} + +#[derive(PartialEq, Eq, Clone, Debug)] +struct Custom { + kind: ErrorKind, + desc: &'static str, + detail: Option +} + +/// A list specifying general categories of I/O error. +#[derive(Copy, PartialEq, Eq, Clone, Debug)] +pub enum ErrorKind { + /// The file was not found. + FileNotFound, + /// The file permissions disallowed access to this file. + PermissionDenied, + /// The connection was refused by the remote server. + ConnectionRefused, + /// The connection was reset by the remote server. + ConnectionReset, + /// The connection was aborted (terminated) by the remote server. + ConnectionAborted, + /// The network operation failed because it was not connected yet. + NotConnected, + /// The operation failed because a pipe was closed. + BrokenPipe, + /// A file already existed with that name. + PathAlreadyExists, + /// No file exists at that location. + PathDoesntExist, + /// The path did not specify the type of file that this operation required. + /// For example, attempting to copy a directory with the `fs::copy()` + /// operation will fail with this error. + MismatchedFileTypeForOperation, + /// The operation temporarily failed (for example, because a signal was + /// received), and retrying may succeed. + ResourceUnavailable, + /// A parameter was incorrect in a way that caused an I/O error not part of + /// this list. + InvalidInput, + /// The I/O operation's timeout expired, causing it to be canceled. + TimedOut, + /// An error returned when an operation could not be completed because a + /// call to `write` returned `Ok(0)`. + /// + /// This typically means that an operation could only succeed if it wrote a + /// particular number of bytes but only a smaller number of bytes could be + /// written. + WriteZero, + /// This operation was interrupted + Interrupted, + /// Any I/O error not part of this list. + Other, +} + +impl Error { + /// Creates a new custom error from a specified kind/description/detail. + pub fn new(kind: ErrorKind, + description: &'static str, + detail: Option) -> Error { + Error { + repr: Repr::Custom(Box::new(Custom { + kind: kind, + desc: description, + detail: detail, + })) + } + } + + /// Returns an error representing the last OS error which occurred. + /// + /// This function reads the value of `errno` for the target platform (e.g. + /// `GetLastError` on Windows) and will return a corresponding instance of + /// `Error` for the error code. + pub fn last_os_error() -> Error { + Error::from_os_error(sys::os::errno() as i32) + } + + /// Creates a new instance of an `Error` from a particular OS error code. + pub fn from_os_error(code: i32) -> Error { + Error { repr: Repr::Os(code) } + } + + /// Return the corresponding `ErrorKind` for this error. + pub fn kind(&self) -> ErrorKind { + match self.repr { + Repr::Os(code) => sys::decode_error_kind(code), + Repr::Custom(ref c) => c.kind, + } + } + + /// Returns a short description for this error message + pub fn description(&self) -> &str { + match self.repr { + Repr::Os(..) => "os error", + Repr::Custom(ref c) => c.desc, + } + } + + /// Returns a detailed error message for this error (if one is available) + pub fn detail(&self) -> Option { + match self.repr { + Repr::Os(code) => Some(sys::os::error_string(code)), + Repr::Custom(ref s) => s.detail.clone(), + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + match self.repr { + Repr::Os(code) => { + let detail = sys::os::error_string(code); + write!(fmt, "{} (os error {})", detail, code) + } + Repr::Custom(ref c) => { + match **c { + Custom { + kind: ErrorKind::Other, + desc: "unknown error", + detail: Some(ref detail) + } => { + write!(fmt, "{}", detail) + } + Custom { detail: None, desc, .. } => + write!(fmt, "{}", desc), + Custom { detail: Some(ref detail), desc, .. } => + write!(fmt, "{} ({})", desc, detail) + } + } + } + } +} + +impl StdError for Error { + fn description(&self) -> &str { + match self.repr { + Repr::Os(..) => "os error", + Repr::Custom(ref c) => c.desc, + } + } +} diff --git a/src/libstd/io/impls.rs b/src/libstd/io/impls.rs new file mode 100644 index 00000000000..7f3ce7924c1 --- /dev/null +++ b/src/libstd/io/impls.rs @@ -0,0 +1,88 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::prelude::*; + +use boxed::Box; +use cmp; +use io::{self, SeekFrom, Read, Write, Seek, BufRead}; +use mem; +use slice; +use vec::Vec; + +// ============================================================================= +// Forwarding implementations + +impl<'a, R: Read + ?Sized> Read for &'a mut R { + fn read(&mut self, buf: &mut [u8]) -> io::Result { (**self).read(buf) } +} +impl<'a, W: Write + ?Sized> Write for &'a mut W { + fn write(&mut self, buf: &[u8]) -> io::Result { (**self).write(buf) } + fn flush(&mut self) -> io::Result<()> { (**self).flush() } +} +impl<'a, S: Seek + ?Sized> Seek for &'a mut S { + fn seek(&mut self, pos: SeekFrom) -> io::Result { (**self).seek(pos) } +} +impl<'a, B: BufRead + ?Sized> BufRead for &'a mut B { + fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() } + fn consume(&mut self, amt: usize) { (**self).consume(amt) } +} + +impl Read for Box { + fn read(&mut self, buf: &mut [u8]) -> io::Result { (**self).read(buf) } +} +impl Write for Box { + fn write(&mut self, buf: &[u8]) -> io::Result { (**self).write(buf) } + fn flush(&mut self) -> io::Result<()> { (**self).flush() } +} +impl Seek for Box { + fn seek(&mut self, pos: SeekFrom) -> io::Result { (**self).seek(pos) } +} +impl BufRead for Box { + fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() } + fn consume(&mut self, amt: usize) { (**self).consume(amt) } +} + +// ============================================================================= +// In-memory buffer implementations + +impl<'a> Read for &'a [u8] { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let amt = cmp::min(buf.len(), self.len()); + let (a, b) = self.split_at(amt); + slice::bytes::copy_memory(buf, a); + *self = b; + Ok(amt) + } +} + +impl<'a> BufRead for &'a [u8] { + fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(*self) } + fn consume(&mut self, amt: usize) { *self = &self[amt..]; } +} + +impl<'a> Write for &'a mut [u8] { + fn write(&mut self, data: &[u8]) -> io::Result { + let amt = cmp::min(data.len(), self.len()); + let (a, b) = mem::replace(self, &mut []).split_at_mut(amt); + slice::bytes::copy_memory(a, &data[..amt]); + *self = b; + Ok(amt) + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } +} + +impl Write for Vec { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.push_all(buf); + Ok(buf.len()) + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } +} diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs new file mode 100644 index 00000000000..0832206a48b --- /dev/null +++ b/src/libstd/io/mod.rs @@ -0,0 +1,948 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Traits, helpers, and type definitions for core I/O functionality. +//! +//! > **NOTE**: This module is very much a work in progress and is under active +//! > development. At this time it is still recommended to use the `old_io` +//! > module while the details of this module shake out. + +#![unstable(feature = "io", + reason = "this new I/O module is still under active deveopment and \ + APIs are subject to tweaks fairly regularly")] + +use cmp; +use unicode::str as core_str; +use error::Error as StdError; +use fmt; +use iter::Iterator; +use marker::Sized; +use mem; +use ops::{Drop, FnOnce}; +use option::Option::{self, Some, None}; +use ptr::PtrExt; +use result::Result::{Ok, Err}; +use result; +use slice::{self, SliceExt}; +use string::String; +use str::{self, StrExt}; +use vec::Vec; + +pub use self::buffered::{BufReader, BufWriter, BufStream, LineWriter}; +pub use self::buffered::IntoInnerError; +pub use self::cursor::Cursor; +pub use self::error::{Result, Error, ErrorKind}; +pub use self::util::{copy, sink, Sink, empty, Empty, repeat, Repeat}; + +pub mod prelude; +mod buffered; +mod cursor; +mod error; +mod impls; +mod util; + +const DEFAULT_BUF_SIZE: usize = 64 * 1024; + +// Acquires a slice of the vector `v` from its length to its capacity +// (uninitialized data), reads into it, and then updates the length. +// +// This function is leveraged to efficiently read some bytes into a destination +// vector without extra copying and taking advantage of the space that's already +// in `v`. +// +// The buffer we're passing down, however, is pointing at uninitialized data +// (the end of a `Vec`), and many operations will be *much* faster if we don't +// have to zero it out. In order to prevent LLVM from generating an `undef` +// value when reads happen from this uninitialized memory, we force LLVM to +// think it's initialized by sending it through a black box. This should prevent +// actual undefined behavior after optimizations. +fn with_end_to_cap(v: &mut Vec, f: F) -> Result + where F: FnOnce(&mut [u8]) -> Result +{ + unsafe { + let n = try!(f({ + let base = v.as_mut_ptr().offset(v.len() as isize); + black_box(slice::from_raw_mut_buf(mem::copy_lifetime(v, &base), + v.capacity() - v.len())) + })); + + // If the closure (typically a `read` implementation) reported that it + // read a larger number of bytes than the vector actually has, we need + // to be sure to clamp the vector to at most its capacity. + let new_len = cmp::min(v.capacity(), v.len() + n); + v.set_len(new_len); + return Ok(n); + } + + // Semi-hack used to prevent LLVM from retaining any assumptions about + // `dummy` over this function call + unsafe fn black_box(mut dummy: T) -> T { + asm!("" :: "r"(&mut dummy) : "memory"); + dummy + } +} + +// A few methods below (read_to_string, read_line) will append data into a +// `String` buffer, but we need to be pretty careful when doing this. The +// implementation will just call `.as_mut_vec()` and then delegate to a +// byte-oriented reading method, but we must ensure that when returning we never +// leave `buf` in a state such that it contains invalid UTF-8 in its bounds. +// +// To this end, we use an RAII guard (to protect against panics) which updates +// the length of the string when it is dropped. This guard initially truncates +// the string to the prior length and only afer we've validated that the +// new contents are valid UTF-8 do we allow it to set a longer length. +// +// The unsafety in this function is twofold: +// +// 1. We're looking at the raw bytes of `buf`, so we take on the burden of UTF-8 +// checks. +// 2. We're passing a raw buffer to the function `f`, and it is expected that +// the function only *appends* bytes to the buffer. We'll get undefined +// behavior if existing bytes are overwritten to have non-UTF-8 data. +fn append_to_string(buf: &mut String, f: F) -> Result<()> + where F: FnOnce(&mut Vec) -> Result<()> +{ + struct Guard<'a> { s: &'a mut Vec, len: usize } + #[unsafe_destructor] + impl<'a> Drop for Guard<'a> { + fn drop(&mut self) { + unsafe { self.s.set_len(self.len); } + } + } + + unsafe { + let mut g = Guard { len: buf.len(), s: buf.as_mut_vec() }; + let ret = f(g.s); + if str::from_utf8(&g.s[g.len..]).is_err() { + ret.and_then(|()| { + Err(Error::new(ErrorKind::InvalidInput, + "stream did not contain valid UTF-8", None)) + }) + } else { + g.len = g.s.len(); + ret + } + } +} + +fn read_to_end(r: &mut R, buf: &mut Vec) -> Result<()> { + loop { + if buf.capacity() == buf.len() { + buf.reserve(DEFAULT_BUF_SIZE); + } + match with_end_to_cap(buf, |b| r.read(b)) { + Ok(0) => return Ok(()), + Ok(_) => {} + Err(ref e) if e.kind() == ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } +} + +/// A trait for objects which are byte-oriented sources. +/// +/// Readers are defined by one method, `read`. Each call to `read` will attempt +/// to pull bytes from this source into a provided buffer. +/// +/// Readers are intended to be composable with one another. Many objects +/// throughout the I/O and related libraries take and provide types which +/// implement the `Read` trait. +pub trait Read { + /// Pull some bytes from this source into the specified buffer, returning + /// how many bytes were read. + /// + /// This function does not provide any guarantees about whether it blocks + /// waiting for data, but if an object needs to block for a read but cannot + /// it will typically signal this via an `Err` return value. + /// + /// If the return value of this method is `Ok(n)`, then it must be + /// guaranteed that `0 <= n <= buf.len()`. A nonzero `n` value indicates + /// that the buffer `buf` has ben filled in with `n` bytes of data from this + /// source. If `n` is `0`, then it can indicate one of two scenarios: + /// + /// 1. This reader has reached its "end of file" and will likely no longer + /// be able to produce bytes. Note that this does not mean that the + /// reader will *always* no longer be able to produce bytes. + /// 2. The buffer specified was 0 bytes in length. + /// + /// No guarantees are provided about the contents of `buf` when this + /// function is called, implementations cannot rely on any property of the + /// contents of `buf` being true. It is recommended that implementations + /// only write data to `buf` instead of reading its contents. + /// + /// # Errors + /// + /// If this function encounters any form of I/O or other error, an error + /// variant will be returned. If an error is returned then it must be + /// guaranteed that no bytes were read. + fn read(&mut self, buf: &mut [u8]) -> Result; + + /// Read all bytes until EOF in this source, placing them into `buf`. + /// + /// All bytes read from this source will be appended to the specified buffer + /// `buf`. This function will return a call to `read` either: + /// + /// 1. Returns `Ok(0)`. + /// 2. Returns an error which is not of the kind `ErrorKind::Interrupted`. + /// + /// Until one of these conditions is met the function will continuously + /// invoke `read` to append more data to `buf`. + /// + /// # Errors + /// + /// If this function encounters an error of the kind + /// `ErrorKind::Interrupted` then the error is ignored and the operation + /// will continue. + /// + /// If any other read error is encountered then this function immediately + /// returns. Any bytes which have already been read will be appended to + /// `buf`. + fn read_to_end(&mut self, buf: &mut Vec) -> Result<()> { + read_to_end(self, buf) + } + + /// Read all bytes until EOF in this source, placing them into `buf`. + /// + /// # Errors + /// + /// If the data in this stream is *not* valid UTF-8 then an error is + /// returned and `buf` is unchanged. + /// + /// See `read_to_end` for other error semantics. + fn read_to_string(&mut self, buf: &mut String) -> Result<()> { + // Note that we do *not* call `.read_to_end()` here. We are passing + // `&mut Vec` (the raw contents of `buf`) into the `read_to_end` + // method to fill it up. An arbitrary implementation could overwrite the + // entire contents of the vector, not just append to it (which is what + // we are expecting). + // + // To prevent extraneously checking the UTF-8-ness of the entire buffer + // we pass it to our hardcoded `read_to_end` implementation which we + // know is guaranteed to only read data into the end of the buffer. + append_to_string(buf, |b| read_to_end(self, b)) + } +} + +/// Extension methods for all instances of `Read`, typically imported through +/// `std::io::prelude::*`. +pub trait ReadExt: Read + Sized { + /// Create a "by reference" adaptor for this instance of `Read`. + /// + /// The returned adaptor also implements `Read` and will simply borrow this + /// current reader. + fn by_ref(&mut self) -> &mut Self { self } + + /// Transform this `Read` instance to an `Iterator` over its bytes. + /// + /// The returned type implements `Iterator` where the `Item` is `Result`. The yielded item is `Ok` if a byte was successfully read and + /// `Err` otherwise for I/O errors. EOF is mapped to returning `None` from + /// this iterator. + fn bytes(self) -> Bytes { + Bytes { inner: self } + } + + /// Transform this `Read` instance to an `Iterator` over `char`s. + /// + /// This adaptor will attempt to interpret this reader as an UTF-8 encoded + /// sequence of characters. The returned iterator will return `None` once + /// EOF is reached for this reader. Otherwise each element yielded will be a + /// `Result` where `E` may contain information about what I/O error + /// occurred or where decoding failed. + /// + /// Currently this adaptor will discard intermediate data read, and should + /// be avoided if this is not desired. + fn chars(self) -> Chars { + Chars { inner: self } + } + + /// Create an adaptor which will chain this stream with another. + /// + /// The returned `Read` instance will first read all bytes from this object + /// until EOF is encountered. Afterwards the output is equivalent to the + /// output of `next`. + fn chain(self, next: R) -> Chain { + Chain { first: self, second: next, done_first: false } + } + + /// Create an adaptor which will read at most `limit` bytes from it. + /// + /// This function returns a new instance of `Read` which will read at most + /// `limit` bytes, after which it will always return EOF (`Ok(0)`). Any + /// read errors will not count towards the number of bytes read and future + /// calls to `read` may succeed. + fn take(self, limit: u64) -> Take { + Take { inner: self, limit: limit } + } + + /// Creates a reader adaptor which will write all read data into the given + /// output stream. + /// + /// Whenever the returned `Read` instance is read it will write the read + /// data to `out`. The current semantics of this implementation imply that + /// a `write` error will not report how much data was initially read. + fn tee(self, out: W) -> Tee { + Tee { reader: self, writer: out } + } +} + +impl ReadExt for T {} + +/// A trait for objects which are byte-oriented sinks. +/// +/// The `write` method will attempt to write some data into the object, +/// returning how many bytes were successfully written. +/// +/// The `flush` method is useful for adaptors and explicit buffers themselves +/// for ensuring that all buffered data has been pushed out to the "true sink". +/// +/// Writers are intended to be composable with one another. Many objects +/// throughout the I/O and related libraries take and provide types which +/// implement the `Write` trait. +pub trait Write { + /// Write a buffer into this object, returning how many bytes were written. + /// + /// This function will attempt to write the entire contents of `buf`, but + /// the entire write may not succeed, or the write may also generate an + /// error. A call to `write` represents *at most one* attempt to write to + /// any wrapped object. + /// + /// Calls to `write` are not guaranteed to block waiting for data to be + /// written, and a write which would otherwise block can indicated through + /// an `Err` variant. + /// + /// If the return value is `Ok(n)` then it must be guaranteed that + /// `0 <= n <= buf.len()`. A return value of `0` typically means that the + /// underlying object is no longer able to accept bytes and will likely not + /// be able to in the future as well, or that the buffer provided is empty. + /// + /// # Errors + /// + /// Each call to `write` may generate an I/O error indicating that the + /// operation could not be completed. If an error is returned then no bytes + /// in the buffer were written to this writer. + /// + /// It is **not** considered an error if the entire buffer could not be + /// written to this writer. + fn write(&mut self, buf: &[u8]) -> Result; + + /// Flush this output stream, ensuring that all intermediately buffered + /// contents reach their destination. + /// + /// # Errors + /// + /// It is considered an error if not all bytes could be written due to + /// I/O errors or EOF being reached. + fn flush(&mut self) -> Result<()>; + + /// Attempts to write an entire buffer into this write. + /// + /// This method will continuously call `write` while there is more data to + /// write. This method will not return until the entire buffer has been + /// successfully written or an error occurs. The first error generated from + /// this method will be returned. + /// + /// # Errors + /// + /// This function will return the first error that `write` returns. + fn write_all(&mut self, mut buf: &[u8]) -> Result<()> { + while buf.len() > 0 { + match self.write(buf) { + Ok(0) => return Err(Error::new(ErrorKind::WriteZero, + "failed to write whole buffer", + None)), + Ok(n) => buf = &buf[n..], + Err(ref e) if e.kind() == ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + Ok(()) + } + + /// Writes a formatted string into this writer, returning any error + /// encountered. + /// + /// This method is primarily used to interface with the `format_args!` + /// macro, but it is rare that this should explicitly be called. The + /// `write!` macro should be favored to invoke this method instead. + /// + /// This function internally uses the `write_all` method on this trait and + /// hence will continuously write data so long as no errors are received. + /// This also means that partial writes are not indicated in this signature. + /// + /// # Errors + /// + /// This function will return any I/O error reported while formatting. + fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<()> { + // Create a shim which translates a Writer to a fmt::Writer and saves + // off I/O errors. instead of discarding them + struct Adaptor<'a, T: ?Sized + 'a> { + inner: &'a mut T, + error: Result<()>, + } + + impl<'a, T: Write + ?Sized> fmt::Writer for Adaptor<'a, T> { + fn write_str(&mut self, s: &str) -> fmt::Result { + match self.inner.write_all(s.as_bytes()) { + Ok(()) => Ok(()), + Err(e) => { + self.error = Err(e); + Err(fmt::Error) + } + } + } + } + + let mut output = Adaptor { inner: self, error: Ok(()) }; + match fmt::write(&mut output, fmt) { + Ok(()) => Ok(()), + Err(..) => output.error + } + } +} + +/// Extension methods for all instances of `Write`, typically imported through +/// `std::io::prelude::*`. +pub trait WriteExt: Write + Sized { + /// Create a "by reference" adaptor for this instance of `Write`. + /// + /// The returned adaptor also implements `Write` and will simply borrow this + /// current writer. + fn by_ref(&mut self) -> &mut Self { self } + + /// Creates a new writer which will write all data to both this writer and + /// another writer. + /// + /// All data written to the returned writer will both be written to `self` + /// as well as `other`. Note that the error semantics of the current + /// implementation do not precisely track where errors happen. For example + /// an error on the second call to `write` will not report that the first + /// call to `write` succeeded. + fn broadcast(self, other: W) -> Broadcast { + Broadcast { first: self, second: other } + } +} + +impl WriteExt for T {} + +/// An object implementing `Seek` internally has some form of cursor which can +/// be moved within a stream of bytes. +/// +/// The stream typically has a fixed size, allowing seeking relative to either +/// end or the current offset. +pub trait Seek { + /// Seek to an offset, in bytes, in a stream + /// + /// A seek beyond the end of a stream is allowed, but seeking before offset + /// 0 is an error. + /// + /// Seeking past the end of the stream does not modify the underlying + /// stream, but the next write may cause the previous data to be filled in + /// with a bit pattern. + /// + /// This method returns the new position within the stream if the seek + /// operation completed successfully. + /// + /// # Errors + /// + /// Seeking to a negative offset is considered an error + fn seek(&mut self, pos: SeekFrom) -> Result; +} + +/// Enumeration of possible methods to seek within an I/O object. +#[derive(Copy, PartialEq, Eq, Clone, Debug)] +pub enum SeekFrom { + /// Set the offset to the provided number of bytes. + Start(u64), + + /// Set the offset to the size of this object plus the specified number of + /// bytes. + /// + /// It is possible to seek beyond the end of an object, but is an error to + /// seek before byte 0. + End(i64), + + /// Set the offset to the current position plus the specified number of + /// bytes. + /// + /// It is possible to seek beyond the end of an object, but is an error to + /// seek before byte 0. + Current(i64), +} + +fn read_until(r: &mut R, delim: u8, buf: &mut Vec) + -> Result<()> { + loop { + let (done, used) = { + let available = match r.fill_buf() { + Ok(n) => n, + Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, + Err(e) => return Err(e) + }; + match available.position_elem(&delim) { + Some(i) => { + buf.push_all(&available[..i + 1]); + (true, i + 1) + } + None => { + buf.push_all(available); + (false, available.len()) + } + } + }; + r.consume(used); + if done || used == 0 { + return Ok(()); + } + } +} + +/// 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 `Read` trait with a few methods that are not +/// possible to reasonably implement with purely a read interface. +pub trait BufRead: Read { + /// Fills the internal buffer of this object, returning the buffer contents. + /// + /// 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. + /// + /// An empty buffer returned indicates that the stream has reached EOF. + /// + /// # Errors + /// + /// This function will return an I/O error if the underlying reader was + /// read, but returned an error. + fn fill_buf(&mut self) -> Result<&[u8]>; + + /// Tells this buffer that `amt` bytes have been consumed from the buffer, + /// so they should no longer be returned in calls to `read`. + fn consume(&mut self, amt: usize); + + /// Read all bytes until the delimiter `byte` is reached. + /// + /// This function will continue to read (and buffer) bytes from the + /// underlying stream until the delimiter or EOF is found. Once found, all + /// bytes up to, and including, the delimiter (if found) will be appended to + /// `buf`. + /// + /// If this buffered reader is currently at EOF, then this function will not + /// place any more bytes into `buf` and will return `Ok(())`. + /// + /// # Errors + /// + /// This function will ignore all instances of `ErrorKind::Interrupted` and + /// will otherwise return any errors returned by `fill_buf`. + /// + /// If an I/O error is encountered then all bytes read so far will be + /// present in `buf` and its length will have been adjusted appropriately. + fn read_until(&mut self, byte: u8, buf: &mut Vec) -> Result<()> { + read_until(self, byte, buf) + } + + /// Read all bytes until a newline byte (the 0xA byte) is reached. + /// + /// This function will continue to read (and buffer) bytes from the + /// underlying stream until the newline delimiter (the 0xA byte) or EOF is + /// found. Once found, all bytes up to, and including, the delimiter (if + /// found) will be appended to `buf`. + /// + /// If this reader is currently at EOF then this function will not modify + /// `buf` and will return `Ok(())`. + /// + /// # Errors + /// + /// This function has the same error semantics as `read_until` and will also + /// return an error if the read bytes are not valid UTF-8. If an I/O error + /// is encountered then `buf` may contain some bytes already read in the + /// event that all data read so far was valid UTF-8. + fn read_line(&mut self, buf: &mut String) -> Result<()> { + // Note that we are not calling the `.read_until` method here, but + // rather our hardcoded implementation. For more details as to why, see + // the comments in `read_to_end`. + append_to_string(buf, |b| read_until(self, b'\n', b)) + } +} + +/// Extension methods for all instances of `BufRead`, typically imported through +/// `std::io::prelude::*`. +pub trait BufReadExt: BufRead + Sized { + /// Returns an iterator over the contents of this reader split on the byte + /// `byte`. + /// + /// The iterator returned from this function will return instances of + /// `io::Result>`. Each vector returned will *not* have the + /// delimiter byte at the end. + /// + /// This function will yield errors whenever `read_until` would have also + /// yielded an error. + fn split(self, byte: u8) -> Split { + Split { buf: self, delim: byte } + } + + /// Returns an iterator over the lines of this reader. + /// + /// The iterator returned from this function will yield instances of + /// `io::Result`. Each string returned will *not* have a newline + /// byte (the 0xA byte) at the end. + /// + /// This function will yield errors whenever `read_string` would have also + /// yielded an error. + fn lines(self) -> Lines { + Lines { buf: self } + } +} + +impl BufReadExt for T {} + +/// A `Write` adaptor which will write data to multiple locations. +/// +/// For more information, see `WriteExt::broadcast`. +pub struct Broadcast { + first: T, + second: U, +} + +impl Write for Broadcast { + fn write(&mut self, data: &[u8]) -> Result { + let n = try!(self.first.write(data)); + // FIXME: what if the write fails? (we wrote something) + try!(self.second.write_all(&data[..n])); + Ok(n) + } + + fn flush(&mut self) -> Result<()> { + self.first.flush().and(self.second.flush()) + } +} + +/// Adaptor to chain together two instances of `Read`. +/// +/// For more information, see `ReadExt::chain`. +pub struct Chain { + first: T, + second: U, + done_first: bool, +} + +impl Read for Chain { + fn read(&mut self, buf: &mut [u8]) -> Result { + if !self.done_first { + match try!(self.first.read(buf)) { + 0 => { self.done_first = true; } + n => return Ok(n), + } + } + self.second.read(buf) + } +} + +/// Reader adaptor which limits the bytes read from an underlying reader. +/// +/// For more information, see `ReadExt::take`. +pub struct Take { + inner: T, + limit: u64, +} + +impl Take { + /// Returns the number of bytes that can be read before this instance will + /// return EOF. + /// + /// # Note + /// + /// This instance may reach EOF after reading fewer bytes than indiccated by + /// this method if the underlying `Read` instance reaches EOF. + pub fn limit(&self) -> u64 { self.limit } +} + +impl Read for Take { + fn read(&mut self, buf: &mut [u8]) -> Result { + let max = cmp::min(buf.len() as u64, self.limit) as usize; + let n = try!(self.inner.read(&mut buf[..max])); + self.limit -= n as u64; + Ok(n) + } +} + +/// An adaptor which will emit all read data to a specified writer as well. +/// +/// For more information see `ReadExt::tee` +pub struct Tee { + reader: R, + writer: W, +} + +impl Read for Tee { + fn read(&mut self, buf: &mut [u8]) -> Result { + let n = try!(self.reader.read(buf)); + // FIXME: what if the write fails? (we read something) + try!(self.writer.write_all(&buf[..n])); + Ok(n) + } +} + +/// A bridge from implementations of `Read` to an `Iterator` of `u8`. +/// +/// See `ReadExt::bytes` for more information. +pub struct Bytes { + inner: R, +} + +impl Iterator for Bytes { + type Item = Result; + + fn next(&mut self) -> Option> { + let mut buf = [0]; + match self.inner.read(&mut buf) { + Ok(0) => None, + Ok(..) => Some(Ok(buf[0])), + Err(e) => Some(Err(e)), + } + } +} + +/// A bridge from implementations of `Read` to an `Iterator` of `char`. +/// +/// See `ReadExt::chars` for more information. +pub struct Chars { + inner: R, +} + +/// An enumeration of possible errors that can be generated from the `Chars` +/// adapter. +#[derive(PartialEq, Clone, Debug)] +pub enum CharsError { + /// Variant representing that the underlying stream was read successfully + /// but it did not contain valid utf8 data. + NotUtf8, + + /// Variant representing that an I/O error occurred. + Other(Error), +} + +impl Iterator for Chars { + type Item = result::Result; + + fn next(&mut self) -> Option> { + let mut buf = [0]; + let first_byte = match self.inner.read(&mut buf) { + Ok(0) => return None, + Ok(..) => buf[0], + Err(e) => return Some(Err(CharsError::Other(e))), + }; + let width = core_str::utf8_char_width(first_byte); + if width == 1 { return Some(Ok(first_byte as char)) } + if width == 0 { return Some(Err(CharsError::NotUtf8)) } + let mut buf = [first_byte, 0, 0, 0]; + { + let mut start = 1; + while start < width { + match self.inner.read(&mut buf[start..width]) { + Ok(0) => return Some(Err(CharsError::NotUtf8)), + Ok(n) => start += n, + Err(e) => return Some(Err(CharsError::Other(e))), + } + } + } + Some(match str::from_utf8(&buf[..width]).ok() { + Some(s) => Ok(s.char_at(0)), + None => Err(CharsError::NotUtf8), + }) + } +} + +impl StdError for CharsError { + fn description(&self) -> &str { + match *self { + CharsError::NotUtf8 => "invalid utf8 encoding", + CharsError::Other(ref e) => e.description(), + } + } + fn cause(&self) -> Option<&StdError> { + match *self { + CharsError::NotUtf8 => None, + CharsError::Other(ref e) => e.cause(), + } + } +} + +impl fmt::Display for CharsError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + CharsError::NotUtf8 => { + "byte stream did not contain valid utf8".fmt(f) + } + CharsError::Other(ref e) => e.fmt(f), + } + } +} + +/// An iterator over the contents of an instance of `BufRead` split on a +/// particular byte. +/// +/// See `BufReadExt::split` for more information. +pub struct Split { + buf: B, + delim: u8, +} + +impl Iterator for Split { + type Item = Result>; + + fn next(&mut self) -> Option>> { + let mut buf = Vec::new(); + match self.buf.read_until(self.delim, &mut buf) { + Ok(()) if buf.len() == 0 => None, + Ok(()) => { + if buf[buf.len() - 1] == self.delim { + buf.pop(); + } + Some(Ok(buf)) + } + Err(e) => Some(Err(e)) + } + } +} + +/// An iterator over the lines of an instance of `BufRead` split on a newline +/// byte. +/// +/// See `BufReadExt::lines` for more information. +pub struct Lines { + buf: B, +} + +impl Iterator for Lines { + type Item = Result; + + fn next(&mut self) -> Option> { + let mut buf = String::new(); + match self.buf.read_line(&mut buf) { + Ok(()) if buf.len() == 0 => None, + Ok(()) => { + if buf.ends_with("\n") { + buf.pop(); + } + Some(Ok(buf)) + } + Err(e) => Some(Err(e)) + } + } +} + +#[cfg(test)] +mod tests { + use prelude::v1::*; + use io::prelude::*; + use super::Cursor; + + #[test] + fn read_until() { + let mut buf = Cursor::new(b"12"); + let mut v = Vec::new(); + assert_eq!(buf.read_until(b'3', &mut v), Ok(())); + assert_eq!(v, b"12"); + + let mut buf = Cursor::new(b"1233"); + let mut v = Vec::new(); + assert_eq!(buf.read_until(b'3', &mut v), Ok(())); + assert_eq!(v, b"123"); + v.truncate(0); + assert_eq!(buf.read_until(b'3', &mut v), Ok(())); + assert_eq!(v, b"3"); + v.truncate(0); + assert_eq!(buf.read_until(b'3', &mut v), Ok(())); + assert_eq!(v, []); + } + + #[test] + fn split() { + let mut buf = Cursor::new(b"12"); + let mut s = buf.split(b'3'); + assert_eq!(s.next(), Some(Ok(vec![b'1', b'2']))); + assert_eq!(s.next(), None); + + let mut buf = Cursor::new(b"1233"); + let mut s = buf.split(b'3'); + assert_eq!(s.next(), Some(Ok(vec![b'1', b'2']))); + assert_eq!(s.next(), Some(Ok(vec![]))); + assert_eq!(s.next(), None); + } + + #[test] + fn read_line() { + let mut buf = Cursor::new(b"12"); + let mut v = String::new(); + assert_eq!(buf.read_line(&mut v), Ok(())); + assert_eq!(v, "12"); + + let mut buf = Cursor::new(b"12\n\n"); + let mut v = String::new(); + assert_eq!(buf.read_line(&mut v), Ok(())); + assert_eq!(v, "12\n"); + v.truncate(0); + assert_eq!(buf.read_line(&mut v), Ok(())); + assert_eq!(v, "\n"); + v.truncate(0); + assert_eq!(buf.read_line(&mut v), Ok(())); + assert_eq!(v, ""); + } + + #[test] + fn lines() { + let mut buf = Cursor::new(b"12"); + let mut s = buf.lines(); + assert_eq!(s.next(), Some(Ok("12".to_string()))); + assert_eq!(s.next(), None); + + let mut buf = Cursor::new(b"12\n\n"); + let mut s = buf.lines(); + assert_eq!(s.next(), Some(Ok("12".to_string()))); + assert_eq!(s.next(), Some(Ok(String::new()))); + assert_eq!(s.next(), None); + } + + #[test] + fn read_to_end() { + let mut c = Cursor::new(b""); + let mut v = Vec::new(); + assert_eq!(c.read_to_end(&mut v), Ok(())); + assert_eq!(v, []); + + let mut c = Cursor::new(b"1"); + let mut v = Vec::new(); + assert_eq!(c.read_to_end(&mut v), Ok(())); + assert_eq!(v, b"1"); + } + + #[test] + fn read_to_string() { + let mut c = Cursor::new(b""); + let mut v = String::new(); + assert_eq!(c.read_to_string(&mut v), Ok(())); + assert_eq!(v, ""); + + let mut c = Cursor::new(b"1"); + let mut v = String::new(); + assert_eq!(c.read_to_string(&mut v), Ok(())); + assert_eq!(v, "1"); + + let mut c = Cursor::new(b"\xff"); + let mut v = String::new(); + assert!(c.read_to_string(&mut v).is_err()); + } +} diff --git a/src/libstd/io/prelude.rs b/src/libstd/io/prelude.rs new file mode 100644 index 00000000000..475ada2ff84 --- /dev/null +++ b/src/libstd/io/prelude.rs @@ -0,0 +1,27 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The I/O Prelude +//! +//! The purpose of this module is to alleviate imports of many common I/O traits +//! by adding a glob import to the top of I/O heavy modules: +//! +//! ``` +//! use std::io::prelude::*; +//! ``` +//! +//! This module contains reexports of many core I/O traits such as `Read`, +//! `Write`, `ReadExt`, and `WriteExt`. Structures and functions are not +//! contained in this module. + +pub use super::{Read, ReadExt, Write, WriteExt, BufRead, BufReadExt}; + +// FIXME: pub use as `Seek` when the name isn't in the actual prelude any more +pub use super::Seek as NewSeek; diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs new file mode 100644 index 00000000000..3d342137c62 --- /dev/null +++ b/src/libstd/io/util.rs @@ -0,0 +1,153 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(missing_copy_implementations)] + +use prelude::v1::*; + +use io::{self, Read, Write, ErrorKind}; + +/// Copies the entire contents of a reader into a writer. +/// +/// This function will continuously read data from `r` and then write it into +/// `w` in a streaming fashion until `r` returns EOF. +/// +/// On success the total number of bytes that were copied from `r` to `w` is +/// returned. +/// +/// # Errors +/// +/// This function will return an error immediately if any call to `read` or +/// `write` returns an error. All instances of `ErrorKind::Interrupted` are +/// handled by this function and the underlying operation is retried. +pub fn copy(r: &mut R, w: &mut W) -> io::Result { + let mut buf = [0; super::DEFAULT_BUF_SIZE]; + let mut written = 0; + loop { + let len = match r.read(&mut buf) { + Ok(0) => return Ok(written), + Ok(len) => len, + Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, + Err(e) => return Err(e), + }; + try!(w.write_all(&buf[..len])); + written += len as u64; + } +} + +/// A reader which is always at EOF. +pub struct Empty { _priv: () } + +/// Creates an instance of an empty reader. +/// +/// All reads from the returned reader will return `Ok(0)`. +pub fn empty() -> Empty { Empty { _priv: () } } + +impl Read for Empty { + fn read(&mut self, _buf: &mut [u8]) -> io::Result { Ok(0) } +} + +/// A reader which infinitely yields one byte. +pub struct Repeat { byte: u8 } + +/// Creates an instance of a reader that infinitely repeats one byte. +/// +/// All reads from this reader will succeed by filling the specified buffer with +/// the given byte. +pub fn repeat(byte: u8) -> Repeat { Repeat { byte: byte } } + +impl Read for Repeat { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + for slot in buf.iter_mut() { + *slot = self.byte; + } + Ok(buf.len()) + } +} + +/// A writer which will move data into the void. +pub struct Sink { _priv: () } + +/// Creates an instance of a writer which will successfully consume all data. +/// +/// All calls to `write` on the returned instance will return `Ok(buf.len())` +/// and the contents of the buffer will not be inspected. +pub fn sink() -> Sink { Sink { _priv: () } } + +impl Write for Sink { + fn write(&mut self, buf: &[u8]) -> io::Result { Ok(buf.len()) } + fn flush(&mut self) -> io::Result<()> { Ok(()) } +} + +#[cfg(test)] +mod test { + use prelude::v1::*; + + use io::prelude::*; + use io::{sink, empty, repeat}; + + #[test] + fn sink_sinks() { + let mut s = sink(); + assert_eq!(s.write(&[]), Ok(0)); + assert_eq!(s.write(&[0]), Ok(1)); + assert_eq!(s.write(&[0; 1024]), Ok(1024)); + assert_eq!(s.by_ref().write(&[0; 1024]), Ok(1024)); + } + + #[test] + fn empty_reads() { + let mut e = empty(); + assert_eq!(e.read(&mut []), Ok(0)); + assert_eq!(e.read(&mut [0]), Ok(0)); + assert_eq!(e.read(&mut [0; 1024]), Ok(0)); + assert_eq!(e.by_ref().read(&mut [0; 1024]), Ok(0)); + } + + #[test] + fn repeat_repeats() { + let mut r = repeat(4); + let mut b = [0; 1024]; + assert_eq!(r.read(&mut b), Ok(1024)); + assert!(b.iter().all(|b| *b == 4)); + } + + #[test] + fn take_some_bytes() { + assert_eq!(repeat(4).take(100).bytes().count(), 100); + assert_eq!(repeat(4).take(100).bytes().next(), Some(Ok(4))); + assert_eq!(repeat(1).take(10).chain(repeat(2).take(10)).bytes().count(), 20); + } + + #[test] + fn tee() { + let mut buf = [0; 10]; + { + let mut ptr: &mut [u8] = &mut buf; + assert_eq!(repeat(4).tee(&mut ptr).take(5).read(&mut [0; 10]), Ok(5)); + } + assert_eq!(buf, [4, 4, 4, 4, 4, 0, 0, 0, 0, 0]); + } + + #[test] + fn broadcast() { + let mut buf1 = [0; 10]; + let mut buf2 = [0; 10]; + { + let mut ptr1: &mut [u8] = &mut buf1; + let mut ptr2: &mut [u8] = &mut buf2; + + assert_eq!((&mut ptr1).broadcast(&mut ptr2) + .write(&[1, 2, 3]), Ok(3)); + } + assert_eq!(buf1, buf2); + assert_eq!(buf1, [1, 2, 3, 0, 0, 0, 0, 0, 0, 0]); + } +} diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index bd4763d7bd4..a46cea7a443 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -128,9 +128,8 @@ #![deny(missing_docs)] -#[cfg(test)] -#[macro_use] -extern crate log; +#[cfg(test)] extern crate test; +#[cfg(test)] #[macro_use] extern crate log; #[macro_use] #[macro_reexport(assert, assert_eq, debug_assert, debug_assert_eq, @@ -248,6 +247,7 @@ pub mod dynamic_lib; pub mod ffi; pub mod fmt; pub mod old_io; +pub mod io; pub mod os; pub mod env; pub mod path; diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index b03b9046966..427cf21ac70 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -18,10 +18,11 @@ use prelude::v1::*; use ffi; -use old_io::{self, IoResult, IoError}; +use io::ErrorKind; use libc; use num::{Int, SignedInt}; use num; +use old_io::{self, IoResult, IoError}; use str; use sys_common::mkerr_libc; @@ -133,6 +134,35 @@ pub fn decode_error_detailed(errno: i32) -> IoError { err } +pub fn decode_error_kind(errno: i32) -> ErrorKind { + match errno as libc::c_int { + libc::ECONNREFUSED => ErrorKind::ConnectionRefused, + libc::ECONNRESET => ErrorKind::ConnectionReset, + libc::EPERM | libc::EACCES => ErrorKind::PermissionDenied, + libc::EPIPE => ErrorKind::BrokenPipe, + libc::ENOTCONN => ErrorKind::NotConnected, + libc::ECONNABORTED => ErrorKind::ConnectionAborted, + libc::EADDRNOTAVAIL => ErrorKind::ConnectionRefused, + libc::EADDRINUSE => ErrorKind::ConnectionRefused, + libc::ENOENT => ErrorKind::FileNotFound, + libc::EISDIR => ErrorKind::InvalidInput, + libc::EINTR => ErrorKind::Interrupted, + libc::EINVAL => ErrorKind::InvalidInput, + libc::ENOTTY => ErrorKind::MismatchedFileTypeForOperation, + libc::ETIMEDOUT => ErrorKind::TimedOut, + libc::ECANCELED => ErrorKind::TimedOut, + libc::consts::os::posix88::EEXIST => ErrorKind::PathAlreadyExists, + + // These two constants can have the same value on some systems, + // but different values on others, so we can't use a match + // clause + x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => + ErrorKind::ResourceUnavailable, + + _ => ErrorKind::Other, + } +} + #[inline] pub fn retry (mut f: F) -> T where T: SignedInt, diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 8dd467eba9e..f1af70e2cf7 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -15,6 +15,7 @@ use prelude::v1::*; use ffi::OsStr; +use io::ErrorKind; use libc; use mem; use old_io::{self, IoResult, IoError}; @@ -143,6 +144,34 @@ pub fn decode_error_detailed(errno: i32) -> IoError { err } +pub fn decode_error_kind(errno: i32) -> ErrorKind { + match errno as libc::c_int { + libc::ERROR_ACCESS_DENIED => ErrorKind::PermissionDenied, + libc::ERROR_ALREADY_EXISTS => ErrorKind::PathAlreadyExists, + libc::ERROR_BROKEN_PIPE => ErrorKind::BrokenPipe, + libc::ERROR_FILE_NOT_FOUND => ErrorKind::FileNotFound, + libc::ERROR_INVALID_FUNCTION => ErrorKind::InvalidInput, + libc::ERROR_INVALID_HANDLE => ErrorKind::MismatchedFileTypeForOperation, + libc::ERROR_INVALID_NAME => ErrorKind::InvalidInput, + libc::ERROR_NOTHING_TO_TERMINATE => ErrorKind::InvalidInput, + libc::ERROR_NO_DATA => ErrorKind::BrokenPipe, + libc::ERROR_OPERATION_ABORTED => ErrorKind::TimedOut, + + libc::WSAEACCES => ErrorKind::PermissionDenied, + libc::WSAEADDRINUSE => ErrorKind::ConnectionRefused, + libc::WSAEADDRNOTAVAIL => ErrorKind::ConnectionRefused, + libc::WSAECONNABORTED => ErrorKind::ConnectionAborted, + libc::WSAECONNREFUSED => ErrorKind::ConnectionRefused, + libc::WSAECONNRESET => ErrorKind::ConnectionReset, + libc::WSAEINVAL => ErrorKind::InvalidInput, + libc::WSAENOTCONN => ErrorKind::NotConnected, + libc::WSAEWOULDBLOCK => ErrorKind::ResourceUnavailable, + + _ => ErrorKind::Other, + } +} + + #[inline] pub fn retry(f: F) -> I where F: FnOnce() -> I { f() } // PR rust-lang/rust/#17020