aboutsummaryrefslogtreecommitdiff
path: root/ctr-std/src/io
diff options
context:
space:
mode:
authorFenrir <[email protected]>2018-01-21 14:06:28 -0700
committerFenrirWolf <[email protected]>2018-01-21 19:16:33 -0700
commit23be3f4885688e5e0011005e2295c75168854c0a (patch)
treedd0850f9c73c489e114a761d5c0757f3dbec3a65 /ctr-std/src/io
parentUpdate CI for Rust nightly-2017-12-01 + other fixes (diff)
downloadctru-rs-23be3f4885688e5e0011005e2295c75168854c0a.tar.xz
ctru-rs-23be3f4885688e5e0011005e2295c75168854c0a.zip
Recreate ctr-std from latest nightly
Diffstat (limited to 'ctr-std/src/io')
-rw-r--r--ctr-std/src/io/buffered.rs281
-rw-r--r--ctr-std/src/io/cursor.rs197
-rw-r--r--ctr-std/src/io/error.rs81
-rw-r--r--ctr-std/src/io/impls.rs47
-rw-r--r--ctr-std/src/io/lazy.rs2
-rw-r--r--ctr-std/src/io/mod.rs708
-rw-r--r--ctr-std/src/io/stdio.rs90
-rw-r--r--ctr-std/src/io/util.rs67
8 files changed, 1121 insertions, 352 deletions
diff --git a/ctr-std/src/io/buffered.rs b/ctr-std/src/io/buffered.rs
index 44dd4e9..4e7db5f 100644
--- a/ctr-std/src/io/buffered.rs
+++ b/ctr-std/src/io/buffered.rs
@@ -15,18 +15,18 @@ use io::prelude::*;
use cmp;
use error;
use fmt;
-use io::{self, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom};
+use io::{self, Initializer, DEFAULT_BUF_SIZE, Error, ErrorKind, SeekFrom};
use memchr;
/// The `BufReader` struct adds buffering to any reader.
///
/// 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.
+/// For example, every call to [`read`][`TcpStream::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.
///
/// [`Read`]: ../../std/io/trait.Read.html
-/// [`read`]: ../../std/net/struct.TcpStream.html#method.read
+/// [`TcpStream::read`]: ../../std/net/struct.TcpStream.html#method.read
/// [`TcpStream`]: ../../std/net/struct.TcpStream.html
///
/// # Examples
@@ -37,11 +37,11 @@ use memchr;
/// use std::fs::File;
///
/// # fn foo() -> std::io::Result<()> {
-/// let mut f = try!(File::open("log.txt"));
+/// let f = File::open("log.txt")?;
/// let mut reader = BufReader::new(f);
///
/// let mut line = String::new();
-/// let len = try!(reader.read_line(&mut line));
+/// let len = reader.read_line(&mut line)?;
/// println!("First line is {} bytes long", len);
/// # Ok(())
/// # }
@@ -64,8 +64,8 @@ impl<R: Read> BufReader<R> {
/// use std::fs::File;
///
/// # fn foo() -> std::io::Result<()> {
- /// let mut f = try!(File::open("log.txt"));
- /// let mut reader = BufReader::new(f);
+ /// let f = File::open("log.txt")?;
+ /// let reader = BufReader::new(f);
/// # Ok(())
/// # }
/// ```
@@ -85,18 +85,23 @@ impl<R: Read> BufReader<R> {
/// use std::fs::File;
///
/// # fn foo() -> std::io::Result<()> {
- /// let mut f = try!(File::open("log.txt"));
- /// let mut reader = BufReader::with_capacity(10, f);
+ /// let f = File::open("log.txt")?;
+ /// let reader = BufReader::with_capacity(10, f);
/// # Ok(())
/// # }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with_capacity(cap: usize, inner: R) -> BufReader<R> {
- BufReader {
- inner: inner,
- buf: vec![0; cap].into_boxed_slice(),
- pos: 0,
- cap: 0,
+ unsafe {
+ let mut buffer = Vec::with_capacity(cap);
+ buffer.set_len(cap);
+ inner.initializer().initialize(&mut buffer);
+ BufReader {
+ inner,
+ buf: buffer.into_boxed_slice(),
+ pos: 0,
+ cap: 0,
+ }
}
}
@@ -111,8 +116,8 @@ impl<R: Read> BufReader<R> {
/// use std::fs::File;
///
/// # fn foo() -> std::io::Result<()> {
- /// let mut f1 = try!(File::open("log.txt"));
- /// let mut reader = BufReader::new(f1);
+ /// let f1 = File::open("log.txt")?;
+ /// let reader = BufReader::new(f1);
///
/// let f2 = reader.get_ref();
/// # Ok(())
@@ -132,7 +137,7 @@ impl<R: Read> BufReader<R> {
/// use std::fs::File;
///
/// # fn foo() -> std::io::Result<()> {
- /// let mut f1 = try!(File::open("log.txt"));
+ /// let f1 = File::open("log.txt")?;
/// let mut reader = BufReader::new(f1);
///
/// let f2 = reader.get_mut();
@@ -142,6 +147,31 @@ impl<R: Read> BufReader<R> {
#[stable(feature = "rust1", since = "1.0.0")]
pub fn get_mut(&mut self) -> &mut R { &mut self.inner }
+ /// Returns `true` if there are no bytes in the internal buffer.
+ ///
+ /// # Examples
+ /// ```
+ /// # #![feature(bufreader_is_empty)]
+ /// use std::io::BufReader;
+ /// use std::io::BufRead;
+ /// use std::fs::File;
+ ///
+ /// # fn foo() -> std::io::Result<()> {
+ /// let f1 = File::open("log.txt")?;
+ /// let mut reader = BufReader::new(f1);
+ /// assert!(reader.is_empty());
+ ///
+ /// if reader.fill_buf()?.len() > 0 {
+ /// assert!(!reader.is_empty());
+ /// }
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[unstable(feature = "bufreader_is_empty", issue = "45323", reason = "recently added")]
+ pub fn is_empty(&self) -> bool {
+ self.pos == self.cap
+ }
+
/// Unwraps this `BufReader`, returning the underlying reader.
///
/// Note that any leftover data in the internal buffer is lost.
@@ -153,8 +183,8 @@ impl<R: Read> BufReader<R> {
/// use std::fs::File;
///
/// # fn foo() -> std::io::Result<()> {
- /// let mut f1 = try!(File::open("log.txt"));
- /// let mut reader = BufReader::new(f1);
+ /// let f1 = File::open("log.txt")?;
+ /// let reader = BufReader::new(f1);
///
/// let f2 = reader.into_inner();
/// # Ok(())
@@ -164,6 +194,31 @@ impl<R: Read> BufReader<R> {
pub fn into_inner(self) -> R { self.inner }
}
+impl<R: Seek> BufReader<R> {
+ /// Seeks relative to the current position. If the new position lies within the buffer,
+ /// the buffer will not be flushed, allowing for more efficient seeks.
+ /// This method does not return the location of the underlying reader, so the caller
+ /// must track this information themselves if it is required.
+ #[unstable(feature = "bufreader_seek_relative", issue = "31100")]
+ pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> {
+ let pos = self.pos as u64;
+ if offset < 0 {
+ if let Some(new_pos) = pos.checked_sub((-offset) as u64) {
+ self.pos = new_pos as usize;
+ return Ok(())
+ }
+ } else {
+ if let Some(new_pos) = pos.checked_add(offset as u64) {
+ if new_pos <= self.cap as u64 {
+ self.pos = new_pos as usize;
+ return Ok(())
+ }
+ }
+ }
+ self.seek(SeekFrom::Current(offset)).map(|_|())
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<R: Read> Read for BufReader<R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
@@ -180,6 +235,11 @@ impl<R: Read> Read for BufReader<R> {
self.consume(nread);
Ok(nread)
}
+
+ // we can't skip unconditionally because of the large buffer case in read.
+ unsafe fn initializer(&self) -> Initializer {
+ self.inner.initializer()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -187,7 +247,10 @@ impl<R: Read> BufRead for BufReader<R> {
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.pos == self.cap {
+ // Branch using `>=` instead of the more correct `==`
+ // to tell the compiler that the pos..cap slice is always valid.
+ if self.pos >= self.cap {
+ debug_assert!(self.pos == self.cap);
self.cap = self.inner.read(&mut self.buf)?;
self.pos = 0;
}
@@ -222,13 +285,17 @@ impl<R: Seek> Seek for BufReader<R> {
/// `.into_inner()` immediately after a seek yields the underlying reader
/// at the same position.
///
+ /// To seek without discarding the internal buffer, use [`seek_relative`].
+ ///
/// See `std::io::Seek` for more details.
///
/// Note: In the edge case where you're seeking with `SeekFrom::Current(n)`
- /// where `n` minus the internal buffer length underflows an `i64`, two
+ /// where `n` minus the internal buffer length overflows an `i64`, two
/// seeks will be performed instead of one. If the second seek returns
/// `Err`, the underlying reader will be left at the same position it would
/// have if you seeked to `SeekFrom::Current(0)`.
+ ///
+ /// [`seek_relative`]: #method.seek_relative
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
let result: u64;
if let SeekFrom::Current(n) = pos {
@@ -258,11 +325,15 @@ impl<R: Seek> Seek for BufReader<R> {
/// Wraps a writer and buffers its output.
///
/// It can be excessively inefficient to work directly with something that
-/// implements [`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 an underlying writer in large, infrequent batches.
+/// implements [`Write`]. For example, every call to
+/// [`write`][`Tcpstream::write`] on [`TcpStream`] results in a system call. A
+/// `BufWriter` keeps an in-memory buffer of data and writes it to an underlying
+/// writer in large, infrequent batches.
///
-/// The buffer will be written out when the writer is dropped.
+/// When the `BufWriter` is dropped, the contents of its buffer will be written
+/// out. However, any errors that happen in the process of flushing the buffer
+/// when the writer is dropped will be ignored. Code that wishes to handle such
+/// errors must manually call [`flush`] before the writer is dropped.
///
/// # Examples
///
@@ -274,8 +345,8 @@ impl<R: Seek> Seek for BufReader<R> {
///
/// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap();
///
-/// for i in 1..10 {
-/// stream.write(&[i]).unwrap();
+/// for i in 0..10 {
+/// stream.write(&[i+1]).unwrap();
/// }
/// ```
///
@@ -290,8 +361,8 @@ impl<R: Seek> Seek for BufReader<R> {
///
/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap());
///
-/// for i in 1..10 {
-/// stream.write(&[i]).unwrap();
+/// for i in 0..10 {
+/// stream.write(&[i+1]).unwrap();
/// }
/// ```
///
@@ -300,8 +371,9 @@ impl<R: Seek> Seek for BufReader<R> {
/// the `stream` is dropped.
///
/// [`Write`]: ../../std/io/trait.Write.html
-/// [`write`]: ../../std/net/struct.TcpStream.html#method.write
+/// [`Tcpstream::write`]: ../../std/net/struct.TcpStream.html#method.write
/// [`TcpStream`]: ../../std/net/struct.TcpStream.html
+/// [`flush`]: #method.flush
#[stable(feature = "rust1", since = "1.0.0")]
pub struct BufWriter<W: Write> {
inner: Option<W>,
@@ -443,6 +515,10 @@ impl<W: Write> BufWriter<W> {
///
/// The buffer is written out before returning the writer.
///
+ /// # Errors
+ ///
+ /// An `Err` will be returned if an error occurs while flushing the buffer.
+ ///
/// # Examples
///
/// ```no_run
@@ -607,6 +683,9 @@ impl<W> fmt::Display for IntoInnerError<W> {
/// completed, rather than the entire buffer at once. Enter `LineWriter`. It
/// does exactly that.
///
+/// Like [`BufWriter`], a `LineWriter`’s buffer will also be flushed when the
+/// `LineWriter` goes out of scope or when its internal buffer is full.
+///
/// [bufwriter]: struct.BufWriter.html
///
/// If there's still a partial line in the buffer when the `LineWriter` is
@@ -629,7 +708,7 @@ impl<W> fmt::Display for IntoInnerError<W> {
/// I took the one less traveled by,
/// And that has made all the difference.";
///
-/// let file = try!(File::create("poem.txt"));
+/// let file = File::create("poem.txt")?;
/// let mut file = LineWriter::new(file);
///
/// for &byte in road_not_taken.iter() {
@@ -637,10 +716,10 @@ impl<W> fmt::Display for IntoInnerError<W> {
/// }
///
/// // let's check we did the right thing.
-/// let mut file = try!(File::open("poem.txt"));
+/// let mut file = File::open("poem.txt")?;
/// let mut contents = String::new();
///
-/// try!(file.read_to_string(&mut contents));
+/// file.read_to_string(&mut contents)?;
///
/// assert_eq!(contents.as_bytes(), &road_not_taken[..]);
/// # Ok(())
@@ -649,6 +728,7 @@ impl<W> fmt::Display for IntoInnerError<W> {
#[stable(feature = "rust1", since = "1.0.0")]
pub struct LineWriter<W: Write> {
inner: BufWriter<W>,
+ need_flush: bool,
}
impl<W: Write> LineWriter<W> {
@@ -661,7 +741,7 @@ impl<W: Write> LineWriter<W> {
/// use std::io::LineWriter;
///
/// # fn foo() -> std::io::Result<()> {
- /// let file = try!(File::create("poem.txt"));
+ /// let file = File::create("poem.txt")?;
/// let file = LineWriter::new(file);
/// # Ok(())
/// # }
@@ -682,14 +762,17 @@ impl<W: Write> LineWriter<W> {
/// use std::io::LineWriter;
///
/// # fn foo() -> std::io::Result<()> {
- /// let file = try!(File::create("poem.txt"));
+ /// let file = File::create("poem.txt")?;
/// let file = LineWriter::with_capacity(100, file);
/// # Ok(())
/// # }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with_capacity(cap: usize, inner: W) -> LineWriter<W> {
- LineWriter { inner: BufWriter::with_capacity(cap, inner) }
+ LineWriter {
+ inner: BufWriter::with_capacity(cap, inner),
+ need_flush: false,
+ }
}
/// Gets a reference to the underlying writer.
@@ -701,7 +784,7 @@ impl<W: Write> LineWriter<W> {
/// use std::io::LineWriter;
///
/// # fn foo() -> std::io::Result<()> {
- /// let file = try!(File::create("poem.txt"));
+ /// let file = File::create("poem.txt")?;
/// let file = LineWriter::new(file);
///
/// let reference = file.get_ref();
@@ -723,7 +806,7 @@ impl<W: Write> LineWriter<W> {
/// use std::io::LineWriter;
///
/// # fn foo() -> std::io::Result<()> {
- /// let file = try!(File::create("poem.txt"));
+ /// let file = File::create("poem.txt")?;
/// let mut file = LineWriter::new(file);
///
/// // we can use reference just like file
@@ -738,6 +821,10 @@ impl<W: Write> LineWriter<W> {
///
/// The internal buffer is written out before returning the writer.
///
+ // # Errors
+ ///
+ /// An `Err` will be returned if an error occurs while flushing the buffer.
+ ///
/// # Examples
///
/// ```
@@ -745,18 +832,21 @@ impl<W: Write> LineWriter<W> {
/// use std::io::LineWriter;
///
/// # fn foo() -> std::io::Result<()> {
- /// let file = try!(File::create("poem.txt"));
+ /// let file = File::create("poem.txt")?;
///
/// let writer: LineWriter<File> = LineWriter::new(file);
///
- /// let file: File = try!(writer.into_inner());
+ /// let file: File = writer.into_inner()?;
/// # Ok(())
/// # }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn into_inner(self) -> Result<W, IntoInnerError<LineWriter<W>>> {
self.inner.into_inner().map_err(|IntoInnerError(buf, e)| {
- IntoInnerError(LineWriter { inner: buf }, e)
+ IntoInnerError(LineWriter {
+ inner: buf,
+ need_flush: false,
+ }, e)
})
}
}
@@ -764,20 +854,46 @@ impl<W: Write> LineWriter<W> {
#[stable(feature = "rust1", since = "1.0.0")]
impl<W: Write> Write for LineWriter<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- match memchr::memrchr(b'\n', buf) {
- Some(i) => {
- let n = self.inner.write(&buf[..i + 1])?;
- if n != i + 1 || self.inner.flush().is_err() {
- // Do not return errors on partial writes.
- return Ok(n);
- }
- self.inner.write(&buf[i + 1..]).map(|i| n + i)
- }
- None => self.inner.write(buf),
+ if self.need_flush {
+ self.flush()?;
+ }
+
+ // Find the last newline character in the buffer provided. If found then
+ // we're going to write all the data up to that point and then flush,
+ // otherewise we just write the whole block to the underlying writer.
+ let i = match memchr::memrchr(b'\n', buf) {
+ Some(i) => i,
+ None => return self.inner.write(buf),
+ };
+
+
+ // Ok, we're going to write a partial amount of the data given first
+ // followed by flushing the newline. After we've successfully written
+ // some data then we *must* report that we wrote that data, so future
+ // errors are ignored. We set our internal `need_flush` flag, though, in
+ // case flushing fails and we need to try it first next time.
+ let n = self.inner.write(&buf[..i + 1])?;
+ self.need_flush = true;
+ if self.flush().is_err() || n != i + 1 {
+ return Ok(n)
+ }
+
+ // At this point we successfully wrote `i + 1` bytes and flushed it out,
+ // meaning that the entire line is now flushed out on the screen. While
+ // we can attempt to finish writing the rest of the data provided.
+ // Remember though that we ignore errors here as we've successfully
+ // written data, so we need to report that.
+ match self.inner.write(&buf[i + 1..]) {
+ Ok(i) => Ok(n + i),
+ Err(_) => Ok(n),
}
}
- fn flush(&mut self) -> io::Result<()> { self.inner.flush() }
+ fn flush(&mut self) -> io::Result<()> {
+ self.inner.flush()?;
+ self.need_flush = false;
+ Ok(())
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -867,6 +983,23 @@ mod tests {
}
#[test]
+ fn test_buffered_reader_seek_relative() {
+ let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
+ let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner));
+
+ assert!(reader.seek_relative(3).is_ok());
+ assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
+ assert!(reader.seek_relative(0).is_ok());
+ assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
+ assert!(reader.seek_relative(1).is_ok());
+ assert_eq!(reader.fill_buf().ok(), Some(&[1][..]));
+ assert!(reader.seek_relative(-1).is_ok());
+ assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..]));
+ assert!(reader.seek_relative(2).is_ok());
+ assert_eq!(reader.fill_buf().ok(), Some(&[2, 3][..]));
+ }
+
+ #[test]
fn test_buffered_reader_seek_underflow() {
// gimmick reader that yields its position modulo 256 for each byte
struct PositionReader {
@@ -1150,4 +1283,44 @@ mod tests {
BufWriter::new(io::sink())
});
}
+
+ struct AcceptOneThenFail {
+ written: bool,
+ flushed: bool,
+ }
+
+ impl Write for AcceptOneThenFail {
+ fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+ if !self.written {
+ assert_eq!(data, b"a\nb\n");
+ self.written = true;
+ Ok(data.len())
+ } else {
+ Err(io::Error::new(io::ErrorKind::NotFound, "test"))
+ }
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ assert!(self.written);
+ assert!(!self.flushed);
+ self.flushed = true;
+ Err(io::Error::new(io::ErrorKind::Other, "test"))
+ }
+ }
+
+ #[test]
+ fn erroneous_flush_retried() {
+ let a = AcceptOneThenFail {
+ written: false,
+ flushed: false,
+ };
+
+ let mut l = LineWriter::new(a);
+ assert_eq!(l.write(b"a\nb\na").unwrap(), 4);
+ assert!(l.get_ref().written);
+ assert!(l.get_ref().flushed);
+ l.get_mut().flushed = false;
+
+ assert_eq!(l.write(b"a").unwrap_err().kind(), io::ErrorKind::Other)
+ }
}
diff --git a/ctr-std/src/io/cursor.rs b/ctr-std/src/io/cursor.rs
index 1b50233..c844770 100644
--- a/ctr-std/src/io/cursor.rs
+++ b/ctr-std/src/io/cursor.rs
@@ -12,7 +12,7 @@ use io::prelude::*;
use core::convert::TryInto;
use cmp;
-use io::{self, SeekFrom, Error, ErrorKind};
+use io::{self, Initializer, SeekFrom, Error, ErrorKind};
/// A `Cursor` wraps another type and provides it with a
/// [`Seek`] implementation.
@@ -45,10 +45,10 @@ use io::{self, SeekFrom, Error, ErrorKind};
///
/// // a library function we've written
/// fn write_ten_bytes_at_end<W: Write + Seek>(writer: &mut W) -> io::Result<()> {
-/// try!(writer.seek(SeekFrom::End(-10)));
+/// writer.seek(SeekFrom::End(-10))?;
///
/// for i in 0..10 {
-/// try!(writer.write(&[i]));
+/// writer.write(&[i])?;
/// }
///
/// // all went well
@@ -60,16 +60,16 @@ use io::{self, SeekFrom, Error, ErrorKind};
/// //
/// // We might want to use a BufReader here for efficiency, but let's
/// // keep this example focused.
-/// let mut file = try!(File::create("foo.txt"));
+/// let mut file = File::create("foo.txt")?;
///
-/// try!(write_ten_bytes_at_end(&mut file));
+/// write_ten_bytes_at_end(&mut file)?;
/// # Ok(())
/// # }
///
/// // now let's write a test
/// #[test]
/// fn test_writes_bytes() {
-/// // setting up a real File is much more slow than an in-memory buffer,
+/// // setting up a real File is much slower than an in-memory buffer,
/// // let's use a cursor instead
/// use std::io::Cursor;
/// let mut buff = Cursor::new(vec![0; 15]);
@@ -89,6 +89,10 @@ pub struct Cursor<T> {
impl<T> Cursor<T> {
/// Creates a new cursor wrapping the provided underlying I/O object.
///
+ /// Cursor initial position is `0` even if underlying object (e.
+ /// g. `Vec`) is not empty. So writing to cursor starts with
+ /// overwriting `Vec` content, not with appending to it.
+ ///
/// # Examples
///
/// ```
@@ -200,18 +204,20 @@ impl<T> Cursor<T> {
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> io::Seek for Cursor<T> where T: AsRef<[u8]> {
fn seek(&mut self, style: SeekFrom) -> io::Result<u64> {
- let pos = match style {
- SeekFrom::Start(n) => { self.pos = n; return Ok(n) }
- SeekFrom::End(n) => self.inner.as_ref().len() as i64 + n,
- SeekFrom::Current(n) => self.pos as i64 + n,
+ let (base_pos, offset) = match style {
+ SeekFrom::Start(n) => { self.pos = n; return Ok(n); }
+ SeekFrom::End(n) => (self.inner.as_ref().len() as u64, n),
+ SeekFrom::Current(n) => (self.pos, n),
};
-
- if pos < 0 {
- Err(Error::new(ErrorKind::InvalidInput,
- "invalid seek to a negative position"))
+ let new_pos = if offset >= 0 {
+ base_pos.checked_add(offset as u64)
} else {
- self.pos = pos as u64;
- Ok(self.pos)
+ base_pos.checked_sub((offset.wrapping_neg()) as u64)
+ };
+ match new_pos {
+ Some(n) => {self.pos = n; Ok(self.pos)}
+ None => Err(Error::new(ErrorKind::InvalidInput,
+ "invalid seek to a negative or overflowing position"))
}
}
}
@@ -223,6 +229,18 @@ impl<T> Read for Cursor<T> where T: AsRef<[u8]> {
self.pos += n as u64;
Ok(n)
}
+
+ fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
+ let n = buf.len();
+ Read::read_exact(&mut self.fill_buf()?, buf)?;
+ self.pos += n as u64;
+ Ok(())
+ }
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -234,14 +252,54 @@ impl<T> BufRead for Cursor<T> where T: AsRef<[u8]> {
fn consume(&mut self, amt: usize) { self.pos += amt as u64; }
}
+// Non-resizing write implementation
+fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result<usize> {
+ let pos = cmp::min(*pos_mut, slice.len() as u64);
+ let amt = (&mut slice[(pos as usize)..]).write(buf)?;
+ *pos_mut += amt as u64;
+ Ok(amt)
+}
+
+// Resizing write implementation
+fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usize> {
+ let pos: usize = (*pos_mut).try_into().map_err(|_| {
+ Error::new(ErrorKind::InvalidInput,
+ "cursor position exceeds maximum possible vector length")
+ })?;
+ // Make sure the internal buffer is as least as big as where we
+ // currently are
+ let len = vec.len();
+ if len < pos {
+ // use `resize` so that the zero filling is as efficient as possible
+ vec.resize(pos, 0);
+ }
+ // 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 = vec.len() - pos;
+ let (left, right) = buf.split_at(cmp::min(space, buf.len()));
+ vec[pos..pos + left.len()].copy_from_slice(left);
+ vec.extend_from_slice(right);
+ }
+
+ // Bump us forward
+ *pos_mut = (pos + buf.len()) as u64;
+ Ok(buf.len())
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> Write for Cursor<&'a mut [u8]> {
#[inline]
- fn write(&mut self, data: &[u8]) -> io::Result<usize> {
- let pos = cmp::min(self.pos, self.inner.len() as u64);
- let amt = (&mut self.inner[(pos as usize)..]).write(data)?;
- self.pos += amt as u64;
- Ok(amt)
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ slice_write(&mut self.pos, self.inner, buf)
+ }
+ fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
+
+#[unstable(feature = "cursor_mut_vec", issue = "30132")]
+impl<'a> Write for Cursor<&'a mut Vec<u8>> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ vec_write(&mut self.pos, self.inner, buf)
}
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
@@ -249,29 +307,7 @@ impl<'a> Write for Cursor<&'a mut [u8]> {
#[stable(feature = "rust1", since = "1.0.0")]
impl Write for Cursor<Vec<u8>> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- let pos: usize = self.position().try_into().map_err(|_| {
- Error::new(ErrorKind::InvalidInput,
- "cursor position exceeds maximum possible vector length")
- })?;
- // Make sure the internal buffer is as least as big as where we
- // currently are
- let len = self.inner.len();
- if len < pos {
- // use `resize` so that the zero filling is as efficient as possible
- self.inner.resize(pos, 0);
- }
- // 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;
- let (left, right) = buf.split_at(cmp::min(space, buf.len()));
- self.inner[pos..pos + left.len()].copy_from_slice(left);
- self.inner.extend_from_slice(right);
- }
-
- // Bump us forward
- self.set_position((pos + buf.len()) as u64);
- Ok(buf.len())
+ vec_write(&mut self.pos, &mut self.inner, buf)
}
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
@@ -280,10 +316,7 @@ impl Write for Cursor<Vec<u8>> {
impl Write for Cursor<Box<[u8]>> {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- let pos = cmp::min(self.pos, self.inner.len() as u64);
- let amt = (&mut self.inner[(pos as usize)..]).write(buf)?;
- self.pos += amt as u64;
- Ok(amt)
+ slice_write(&mut self.pos, &mut self.inner, buf)
}
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
@@ -314,6 +347,17 @@ mod tests {
}
#[test]
+ fn test_mem_mut_writer() {
+ let mut vec = Vec::new();
+ let mut writer = Cursor::new(&mut vec);
+ assert_eq!(writer.write(&[0]).unwrap(), 1);
+ assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
+ assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
+ let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
+ assert_eq!(&writer.get_ref()[..], b);
+ }
+
+ #[test]
fn test_box_slice_writer() {
let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
assert_eq!(writer.position(), 0);
@@ -445,7 +489,7 @@ mod tests {
#[test]
fn test_slice_reader() {
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
- let mut reader = &mut &in_buf[..];
+ let reader = &mut &in_buf[..];
let mut buf = [];
assert_eq!(reader.read(&mut buf).unwrap(), 0);
let mut buf = [0];
@@ -465,6 +509,24 @@ mod tests {
}
#[test]
+ fn test_read_exact() {
+ let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
+ let reader = &mut &in_buf[..];
+ let mut buf = [];
+ assert!(reader.read_exact(&mut buf).is_ok());
+ let mut buf = [8];
+ assert!(reader.read_exact(&mut buf).is_ok());
+ assert_eq!(buf[0], 0);
+ assert_eq!(reader.len(), 7);
+ let mut buf = [0, 0, 0, 0, 0, 0, 0];
+ assert!(reader.read_exact(&mut buf).is_ok());
+ assert_eq!(buf, [1, 2, 3, 4, 5, 6, 7]);
+ assert_eq!(reader.len(), 0);
+ let mut buf = [0];
+ assert!(reader.read_exact(&mut buf).is_err());
+ }
+
+ #[test]
fn test_buf_reader() {
let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7];
let mut reader = Cursor::new(&in_buf[..]);
@@ -527,6 +589,43 @@ mod tests {
}
#[test]
+ fn seek_past_i64() {
+ let buf = [0xff];
+ let mut r = Cursor::new(&buf[..]);
+ assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
+ assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
+ assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
+ assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
+ assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
+ assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
+
+ let mut r = Cursor::new(vec![10]);
+ assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
+ assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
+ assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
+ assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
+ assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
+ assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
+
+ let mut buf = [0];
+ let mut r = Cursor::new(&mut buf[..]);
+ assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
+ assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
+ assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
+ assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
+ assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
+ assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
+
+ let mut r = Cursor::new(vec![10].into_boxed_slice());
+ assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6);
+ assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6);
+ assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006);
+ assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006);
+ assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err());
+ assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6);
+ }
+
+ #[test]
fn seek_before_0() {
let buf = [0xff];
let mut r = Cursor::new(&buf[..]);
diff --git a/ctr-std/src/io/error.rs b/ctr-std/src/io/error.rs
index 795c89c..f0b41f3 100644
--- a/ctr-std/src/io/error.rs
+++ b/ctr-std/src/io/error.rs
@@ -17,17 +17,21 @@ use convert::From;
/// A specialized [`Result`](../result/enum.Result.html) type for I/O
/// operations.
///
-/// This type is broadly used across `std::io` for any operation which may
+/// This type is broadly used across [`std::io`] for any operation which may
/// produce an error.
///
-/// This typedef is generally used to avoid writing out `io::Error` directly and
-/// is otherwise a direct mapping to `Result`.
+/// This typedef is generally used to avoid writing out [`io::Error`] directly and
+/// is otherwise a direct mapping to [`Result`].
///
-/// While usual Rust style is to import types directly, aliases of `Result`
-/// often are not, to make it easier to distinguish between them. `Result` is
-/// generally assumed to be `std::result::Result`, and so users of this alias
+/// While usual Rust style is to import types directly, aliases of [`Result`]
+/// often are not, to make it easier to distinguish between them. [`Result`] is
+/// generally assumed to be [`std::result::Result`][`Result`], and so users of this alias
/// will generally use `io::Result` instead of shadowing the prelude's import
-/// of `std::result::Result`.
+/// of [`std::result::Result`][`Result`].
+///
+/// [`std::io`]: ../io/index.html
+/// [`io::Error`]: ../io/struct.Error.html
+/// [`Result`]: ../result/enum.Result.html
///
/// # Examples
///
@@ -39,7 +43,7 @@ use convert::From;
/// fn get_string() -> io::Result<String> {
/// let mut buffer = String::new();
///
-/// try!(io::stdin().read_line(&mut buffer));
+/// io::stdin().read_line(&mut buffer)?;
///
/// Ok(buffer)
/// }
@@ -47,20 +51,29 @@ use convert::From;
#[stable(feature = "rust1", since = "1.0.0")]
pub type Result<T> = result::Result<T, Error>;
-/// The error type for I/O operations of the `Read`, `Write`, `Seek`, and
+/// 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`].
///
+/// [`Read`]: ../io/trait.Read.html
+/// [`Write`]: ../io/trait.Write.html
+/// [`Seek`]: ../io/trait.Seek.html
/// [`ErrorKind`]: enum.ErrorKind.html
-#[derive(Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Error {
repr: Repr,
}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for Error {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(&self.repr, f)
+ }
+}
+
enum Repr {
Os(i32),
Simple(ErrorKind),
@@ -140,13 +153,13 @@ pub enum ErrorKind {
#[stable(feature = "rust1", since = "1.0.0")]
TimedOut,
/// An error returned when an operation could not be completed because a
- /// call to [`write()`] returned [`Ok(0)`].
+ /// 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.
///
- /// [`write()`]: ../../std/io/trait.Write.html#tymethod.write
+ /// [`write`]: ../../std/io/trait.Write.html#tymethod.write
/// [`Ok(0)`]: ../../std/io/type.Result.html
#[stable(feature = "rust1", since = "1.0.0")]
WriteZero,
@@ -208,6 +221,7 @@ impl ErrorKind {
/// the heap (for normal construction via Error::new) is too costly.
#[stable(feature = "io_error_from_errorkind", since = "1.14.0")]
impl From<ErrorKind> for Error {
+ #[inline]
fn from(kind: ErrorKind) -> Error {
Error {
repr: Repr::Simple(kind)
@@ -244,8 +258,8 @@ impl Error {
fn _new(kind: ErrorKind, error: Box<error::Error+Send+Sync>) -> Error {
Error {
repr: Repr::Custom(Box::new(Custom {
- kind: kind,
- error: error,
+ kind,
+ error,
}))
}
}
@@ -388,12 +402,12 @@ impl Error {
/// impl MyError {
/// fn new() -> MyError {
/// MyError {
- /// v: "oh no!".to_owned()
+ /// v: "oh no!".to_string()
/// }
/// }
///
/// fn change_message(&mut self, new_message: &str) {
- /// self.v = new_message.to_owned();
+ /// self.v = new_message.to_string();
/// }
/// }
///
@@ -503,10 +517,12 @@ impl Error {
impl fmt::Debug for Repr {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match *self {
- Repr::Os(ref code) =>
- fmt.debug_struct("Os").field("code", code)
- .field("message", &sys::os::error_string(*code)).finish(),
- Repr::Custom(ref c) => fmt.debug_tuple("Custom").field(c).finish(),
+ Repr::Os(code) =>
+ fmt.debug_struct("Os")
+ .field("code", &code)
+ .field("kind", &sys::decode_error_kind(code))
+ .field("message", &sys::os::error_string(code)).finish(),
+ Repr::Custom(ref c) => fmt::Debug::fmt(&c, fmt),
Repr::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(),
}
}
@@ -551,17 +567,36 @@ fn _assert_error_is_sync_send() {
#[cfg(test)]
mod test {
- use super::{Error, ErrorKind};
+ use super::{Error, ErrorKind, Repr, Custom};
use error;
use fmt;
use sys::os::error_string;
+ use sys::decode_error_kind;
#[test]
fn test_debug_error() {
let code = 6;
let msg = error_string(code);
- let err = Error { repr: super::Repr::Os(code) };
- let expected = format!("Error {{ repr: Os {{ code: {:?}, message: {:?} }} }}", code, msg);
+ let kind = decode_error_kind(code);
+ let err = Error {
+ repr: Repr::Custom(box Custom {
+ kind: ErrorKind::InvalidInput,
+ error: box Error {
+ repr: super::Repr::Os(code)
+ },
+ })
+ };
+ let expected = format!(
+ "Custom {{ \
+ kind: InvalidInput, \
+ error: Os {{ \
+ code: {:?}, \
+ kind: {:?}, \
+ message: {:?} \
+ }} \
+ }}",
+ code, kind, msg
+ );
assert_eq!(format!("{:?}", err), expected);
}
diff --git a/ctr-std/src/io/impls.rs b/ctr-std/src/io/impls.rs
index 6b26c01..fe1179a 100644
--- a/ctr-std/src/io/impls.rs
+++ b/ctr-std/src/io/impls.rs
@@ -9,7 +9,7 @@
// except according to those terms.
use cmp;
-use io::{self, SeekFrom, Read, Write, Seek, BufRead, Error, ErrorKind};
+use io::{self, SeekFrom, Read, Initializer, Write, Seek, BufRead, Error, ErrorKind};
use fmt;
use mem;
@@ -24,6 +24,11 @@ impl<'a, R: Read + ?Sized> Read for &'a mut R {
}
#[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ (**self).initializer()
+ }
+
+ #[inline]
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
(**self).read_to_end(buf)
}
@@ -88,6 +93,11 @@ impl<R: Read + ?Sized> Read for Box<R> {
}
#[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ (**self).initializer()
+ }
+
+ #[inline]
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
(**self).read_to_end(buf)
}
@@ -157,22 +167,53 @@ impl<'a> Read for &'a [u8] {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let amt = cmp::min(buf.len(), self.len());
let (a, b) = self.split_at(amt);
- buf[..amt].copy_from_slice(a);
+
+ // First check if the amount of bytes we want to read is small:
+ // `copy_from_slice` will generally expand to a call to `memcpy`, and
+ // for a single byte the overhead is significant.
+ if amt == 1 {
+ buf[0] = a[0];
+ } else {
+ buf[..amt].copy_from_slice(a);
+ }
+
*self = b;
Ok(amt)
}
#[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+
+ #[inline]
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
if buf.len() > self.len() {
return Err(Error::new(ErrorKind::UnexpectedEof,
"failed to fill whole buffer"));
}
let (a, b) = self.split_at(buf.len());
- buf.copy_from_slice(a);
+
+ // First check if the amount of bytes we want to read is small:
+ // `copy_from_slice` will generally expand to a call to `memcpy`, and
+ // for a single byte the overhead is significant.
+ if buf.len() == 1 {
+ buf[0] = a[0];
+ } else {
+ buf.copy_from_slice(a);
+ }
+
*self = b;
Ok(())
}
+
+ #[inline]
+ fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
+ buf.extend_from_slice(*self);
+ let len = self.len();
+ *self = &self[len..];
+ Ok(len)
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
diff --git a/ctr-std/src/io/lazy.rs b/ctr-std/src/io/lazy.rs
index ce205c3..9cef4e3 100644
--- a/ctr-std/src/io/lazy.rs
+++ b/ctr-std/src/io/lazy.rs
@@ -27,7 +27,7 @@ impl<T: Send + Sync + 'static> Lazy<T> {
Lazy {
lock: Mutex::new(),
ptr: Cell::new(ptr::null_mut()),
- init: init
+ init,
}
}
diff --git a/ctr-std/src/io/mod.rs b/ctr-std/src/io/mod.rs
index 58788cd..33d11eb 100644
--- a/ctr-std/src/io/mod.rs
+++ b/ctr-std/src/io/mod.rs
@@ -21,7 +21,8 @@
//! of other types, and you can implement them for your types too. As such,
//! you'll see a few different types of I/O throughout the documentation in
//! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec<T>`]s. For
-//! example, [`Read`] adds a [`read()`] method, which we can use on `File`s:
+//! example, [`Read`] adds a [`read`][`Read::read`] method, which we can use on
+//! [`File`]s:
//!
//! ```
//! use std::io;
@@ -106,7 +107,7 @@
//! ```
//!
//! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call
-//! to [`write()`]:
+//! to [`write`][`Write::write`]:
//!
//! ```
//! use std::io;
@@ -145,6 +146,18 @@
//! # }
//! ```
//!
+//! Note that you cannot use the [`?` operator] in functions that do not return
+//! a [`Result<T, E>`][`Result`] (e.g. `main`). Instead, you can call [`.unwrap()`]
+//! or `match` on the return value to catch any possible errors:
+//!
+//! ```
+//! use std::io;
+//!
+//! let mut input = String::new();
+//!
+//! io::stdin().read_line(&mut input).unwrap();
+//! ```
+//!
//! And a very common source of output is standard output:
//!
//! ```
@@ -157,7 +170,7 @@
//! # }
//! ```
//!
-//! Of course, using [`io::stdout()`] directly is less common than something like
+//! Of course, using [`io::stdout`] directly is less common than something like
//! [`println!`].
//!
//! ## Iterator types
@@ -245,13 +258,15 @@
//! [`Vec<T>`]: ../vec/struct.Vec.html
//! [`BufReader`]: struct.BufReader.html
//! [`BufWriter`]: struct.BufWriter.html
-//! [`write()`]: trait.Write.html#tymethod.write
-//! [`io::stdout()`]: fn.stdout.html
+//! [`Write::write`]: trait.Write.html#tymethod.write
+//! [`io::stdout`]: fn.stdout.html
//! [`println!`]: ../macro.println.html
//! [`Lines`]: struct.Lines.html
//! [`io::Result`]: type.Result.html
-//! [`?` operator]: ../../book/syntax-index.html
-//! [`read()`]: trait.Read.html#tymethod.read
+//! [`?` operator]: ../../book/first-edition/syntax-index.html
+//! [`Read::read`]: trait.Read.html#tymethod.read
+//! [`Result`]: ../result/enum.Result.html
+//! [`.unwrap()`]: ../result/enum.Result.html#method.unwrap
#![stable(feature = "rust1", since = "1.0.0")]
@@ -262,6 +277,7 @@ use fmt;
use result;
use str;
use memchr;
+use ptr;
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::buffered::{BufReader, BufWriter, LineWriter};
@@ -274,10 +290,12 @@ pub use self::error::{Result, Error, ErrorKind};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::util::{copy, sink, Sink, empty, Empty, repeat, Repeat};
#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::stdio::{stdin, stdout, stderr, _print, Stdin, Stdout, Stderr};
+pub use self::stdio::{stdin, stdout, stderr, Stdin, Stdout, Stderr};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::stdio::{StdoutLock, StderrLock, StdinLock};
-#[unstable(feature = "libstd_io_internals", issue = "0")]
+#[unstable(feature = "print_internals", issue = "0")]
+pub use self::stdio::{_print, _eprint};
+#[unstable(feature = "libstd_io_internals", issue = "42788")]
#[doc(no_inline, hidden)]
pub use self::stdio::{set_panic, set_print};
@@ -292,6 +310,14 @@ mod stdio;
const DEFAULT_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;
+struct Guard<'a> { buf: &'a mut Vec<u8>, len: usize }
+
+impl<'a> Drop for Guard<'a> {
+ fn drop(&mut self) {
+ unsafe { self.buf.set_len(self.len); }
+ }
+}
+
// 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
@@ -313,23 +339,16 @@ const DEFAULT_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;
fn append_to_string<F>(buf: &mut String, f: F) -> Result<usize>
where F: FnOnce(&mut Vec<u8>) -> Result<usize>
{
- struct Guard<'a> { s: &'a mut Vec<u8>, len: usize }
- 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() {
+ let mut g = Guard { len: buf.len(), buf: buf.as_mut_vec() };
+ let ret = f(g.buf);
+ if str::from_utf8(&g.buf[g.len..]).is_err() {
ret.and_then(|_| {
Err(Error::new(ErrorKind::InvalidData,
"stream did not contain valid UTF-8"))
})
} else {
- g.len = g.s.len();
+ g.len = g.buf.len();
ret
}
}
@@ -341,25 +360,29 @@ fn append_to_string<F>(buf: &mut String, f: F) -> Result<usize>
// of data to return. Simply tacking on an extra DEFAULT_BUF_SIZE space every
// time is 4,500 times (!) slower than this if the reader has a very small
// amount of data to return.
+//
+// Because we're extending the buffer with uninitialized data for trusted
+// readers, we need to make sure to truncate that if any of this panics.
fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize> {
let start_len = buf.len();
- let mut len = start_len;
- let mut new_write_size = 16;
+ let mut g = Guard { len: buf.len(), buf: buf };
let ret;
loop {
- if len == buf.len() {
- if new_write_size < DEFAULT_BUF_SIZE {
- new_write_size *= 2;
+ if g.len == g.buf.len() {
+ unsafe {
+ g.buf.reserve(32);
+ let capacity = g.buf.capacity();
+ g.buf.set_len(capacity);
+ r.initializer().initialize(&mut g.buf[g.len..]);
}
- buf.resize(len + new_write_size, 0);
}
- match r.read(&mut buf[len..]) {
+ match r.read(&mut g.buf[g.len..]) {
Ok(0) => {
- ret = Ok(len - start_len);
+ ret = Ok(g.len - start_len);
break;
}
- Ok(n) => len += n,
+ Ok(n) => g.len += n,
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
Err(e) => {
ret = Err(e);
@@ -368,39 +391,33 @@ fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize>
}
}
- buf.truncate(len);
ret
}
/// The `Read` trait allows for reading bytes from a source.
///
-/// Implementors of the `Read` trait are sometimes called 'readers'.
+/// Implementors of the `Read` trait are called 'readers'.
///
-/// Readers are defined by one required method, `read()`. Each call to `read`
+/// Readers are defined by one required method, [`read()`]. Each call to [`read()`]
/// will attempt to pull bytes from this source into a provided buffer. A
-/// number of other methods are implemented in terms of `read()`, giving
+/// number of other methods are implemented in terms of [`read()`], giving
/// implementors a number of ways to read bytes while only needing to implement
/// a single method.
///
/// Readers are intended to be composable with one another. Many implementors
-/// throughout `std::io` take and provide types which implement the `Read`
+/// throughout [`std::io`] take and provide types which implement the `Read`
/// trait.
///
-/// Please note that each call to `read` may involve a system call, and
-/// therefore, using something that implements [`BufRead`][bufread], such as
-/// [`BufReader`][bufreader], will be more efficient.
-///
-/// [bufread]: trait.BufRead.html
-/// [bufreader]: struct.BufReader.html
+/// Please note that each call to [`read()`] may involve a system call, and
+/// therefore, using something that implements [`BufRead`], such as
+/// [`BufReader`], will be more efficient.
///
/// # Examples
///
-/// [`File`][file]s implement `Read`:
-///
-/// [file]: ../fs/struct.File.html
+/// [`File`]s implement `Read`:
///
/// ```
-/// use std::io;
+/// # use std::io;
/// use std::io::prelude::*;
/// use std::fs::File;
///
@@ -423,16 +440,43 @@ fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<usize>
/// # Ok(())
/// # }
/// ```
+///
+/// Read from [`&str`] because [`&[u8]`][slice] implements `Read`:
+///
+/// ```
+/// # use std::io;
+/// use std::io::prelude::*;
+///
+/// # fn foo() -> io::Result<()> {
+/// let mut b = "This string will be read".as_bytes();
+/// let mut buffer = [0; 10];
+///
+/// // read up to 10 bytes
+/// b.read(&mut buffer)?;
+///
+/// // etc... it works exactly as a File does!
+/// # Ok(())
+/// # }
+/// ```
+///
+/// [`read()`]: trait.Read.html#tymethod.read
+/// [`std::io`]: ../../std/io/index.html
+/// [`File`]: ../fs/struct.File.html
+/// [`BufRead`]: trait.BufRead.html
+/// [`BufReader`]: struct.BufReader.html
+/// [`&str`]: ../../std/primitive.str.html
+/// [slice]: ../../std/primitive.slice.html
#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(spotlight)]
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.
+ /// it will typically signal this via an [`Err`] return value.
///
- /// If the return value of this method is `Ok(n)`, then it must be
+ /// 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 been filled in with `n` bytes of data from this
/// source. If `n` is `0`, then it can indicate one of two scenarios:
@@ -453,11 +497,17 @@ pub trait Read {
/// variant will be returned. If an error is returned then it must be
/// guaranteed that no bytes were read.
///
+ /// An error of the [`ErrorKind::Interrupted`] kind is non-fatal and the read
+ /// operation should be retried if there is nothing else to do.
+ ///
/// # Examples
///
- /// [`File`][file]s implement `Read`:
+ /// [`File`]s implement `Read`:
///
- /// [file]: ../fs/struct.File.html
+ /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+ /// [`Ok(n)`]: ../../std/result/enum.Result.html#variant.Ok
+ /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+ /// [`File`]: ../fs/struct.File.html
///
/// ```
/// use std::io;
@@ -468,7 +518,7 @@ pub trait Read {
/// let mut f = File::open("foo.txt")?;
/// let mut buffer = [0; 10];
///
- /// // read 10 bytes
+ /// // read up to 10 bytes
/// f.read(&mut buffer[..])?;
/// # Ok(())
/// # }
@@ -476,19 +526,47 @@ pub trait Read {
#[stable(feature = "rust1", since = "1.0.0")]
fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
+ /// Determines if this `Read`er can work with buffers of uninitialized
+ /// memory.
+ ///
+ /// The default implementation returns an initializer which will zero
+ /// buffers.
+ ///
+ /// If a `Read`er guarantees that it can work properly with uninitialized
+ /// memory, it should call [`Initializer::nop()`]. See the documentation for
+ /// [`Initializer`] for details.
+ ///
+ /// The behavior of this method must be independent of the state of the
+ /// `Read`er - the method only takes `&self` so that it can be used through
+ /// trait objects.
+ ///
+ /// # Safety
+ ///
+ /// This method is unsafe because a `Read`er could otherwise return a
+ /// non-zeroing `Initializer` from another `Read` type without an `unsafe`
+ /// block.
+ ///
+ /// [`Initializer::nop()`]: ../../std/io/struct.Initializer.html#method.nop
+ /// [`Initializer`]: ../../std/io/struct.Initializer.html
+ #[unstable(feature = "read_initializer", issue = "42788")]
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::zeroing()
+ }
+
/// 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 continuously call `read` to append more data to
- /// `buf` until `read` returns either `Ok(0)` or an error of
- /// non-`ErrorKind::Interrupted` kind.
+ /// `buf`. This function will continuously call [`read()`] to append more data to
+ /// `buf` until [`read()`] returns either [`Ok(0)`] or an error of
+ /// non-[`ErrorKind::Interrupted`] kind.
///
/// If successful, this function will return the total number of bytes read.
///
/// # Errors
///
/// If this function encounters an error of the kind
- /// `ErrorKind::Interrupted` then the error is ignored and the operation
+ /// [`ErrorKind::Interrupted`] then the error is ignored and the operation
/// will continue.
///
/// If any other read error is encountered then this function immediately
@@ -497,9 +575,12 @@ pub trait Read {
///
/// # Examples
///
- /// [`File`][file]s implement `Read`:
+ /// [`File`]s implement `Read`:
///
- /// [file]: ../fs/struct.File.html
+ /// [`read()`]: trait.Read.html#tymethod.read
+ /// [`Ok(0)`]: ../../std/result/enum.Result.html#variant.Ok
+ /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+ /// [`File`]: ../fs/struct.File.html
///
/// ```
/// use std::io;
@@ -520,7 +601,7 @@ pub trait Read {
read_to_end(self, buf)
}
- /// Read all bytes until EOF in this source, placing them into `buf`.
+ /// Read all bytes until EOF in this source, appending them to `buf`.
///
/// If successful, this function returns the number of bytes which were read
/// and appended to `buf`.
@@ -530,7 +611,7 @@ pub trait Read {
/// If the data in this stream is *not* valid UTF-8 then an error is
/// returned and `buf` is unchanged.
///
- /// See [`read_to_end()`][readtoend] for other error semantics.
+ /// See [`read_to_end`][readtoend] for other error semantics.
///
/// [readtoend]: #method.read_to_end
///
@@ -580,11 +661,11 @@ pub trait Read {
/// # Errors
///
/// If this function encounters an error of the kind
- /// `ErrorKind::Interrupted` then the error is ignored and the operation
+ /// [`ErrorKind::Interrupted`] then the error is ignored and the operation
/// will continue.
///
/// If this function encounters an "end of file" before completely filling
- /// the buffer, it returns an error of the kind `ErrorKind::UnexpectedEof`.
+ /// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`].
/// The contents of `buf` are unspecified in this case.
///
/// If any other read error is encountered then this function immediately
@@ -596,9 +677,11 @@ pub trait Read {
///
/// # Examples
///
- /// [`File`][file]s implement `Read`:
+ /// [`File`]s implement `Read`:
///
- /// [file]: ../fs/struct.File.html
+ /// [`File`]: ../fs/struct.File.html
+ /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+ /// [`ErrorKind::UnexpectedEof`]: ../../std/io/enum.ErrorKind.html#variant.UnexpectedEof
///
/// ```
/// use std::io;
@@ -669,18 +752,25 @@ pub trait Read {
#[stable(feature = "rust1", since = "1.0.0")]
fn by_ref(&mut self) -> &mut Self where Self: Sized { self }
- /// Transforms this `Read` instance to an `Iterator` over its bytes.
+ /// Transforms this `Read` instance to an [`Iterator`] over its bytes.
///
- /// The returned type implements `Iterator` where the `Item` is `Result<u8,
- /// R::Err>`. 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.
+ /// The returned type implements [`Iterator`] where the `Item` is
+ /// [`Result`]`<`[`u8`]`, `[`io::Error`]`>`.
+ /// The yielded item is [`Ok`] if a byte was successfully read and [`Err`]
+ /// otherwise. EOF is mapped to returning [`None`] from this iterator.
///
/// # Examples
///
/// [`File`][file]s implement `Read`:
///
/// [file]: ../fs/struct.File.html
+ /// [`Iterator`]: ../../std/iter/trait.Iterator.html
+ /// [`Result`]: ../../std/result/enum.Result.html
+ /// [`io::Error`]: ../../std/io/struct.Error.html
+ /// [`u8`]: ../../std/primitive.u8.html
+ /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
+ /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
///
/// ```
/// use std::io;
@@ -701,12 +791,12 @@ pub trait Read {
Bytes { inner: self }
}
- /// Transforms this `Read` instance to an `Iterator` over `char`s.
+ /// Transforms this `Read` instance to an [`Iterator`] over [`char`]s.
///
/// This adaptor will attempt to interpret this reader as a UTF-8 encoded
- /// sequence of characters. The returned iterator will return `None` once
+ /// sequence of characters. The returned iterator will return [`None`] once
/// EOF is reached for this reader. Otherwise each element yielded will be a
- /// `Result<char, E>` where `E` may contain information about what I/O error
+ /// [`Result`]`<`[`char`]`, E>` 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
@@ -714,9 +804,13 @@ pub trait Read {
///
/// # Examples
///
- /// [`File`][file]s implement `Read`:
+ /// [`File`]s implement `Read`:
///
- /// [file]: ../fs/struct.File.html
+ /// [`File`]: ../fs/struct.File.html
+ /// [`Iterator`]: ../../std/iter/trait.Iterator.html
+ /// [`Result`]: ../../std/result/enum.Result.html
+ /// [`char`]: ../../std/primitive.char.html
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
///
/// ```
/// #![feature(io)]
@@ -779,15 +873,17 @@ pub trait Read {
/// Creates 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
+ /// `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.
+ /// calls to [`read()`] may succeed.
///
/// # Examples
///
- /// [`File`][file]s implement `Read`:
+ /// [`File`]s implement `Read`:
///
- /// [file]: ../fs/struct.File.html
+ /// [`File`]: ../fs/struct.File.html
+ /// [`Ok(0)`]: ../../std/result/enum.Result.html#variant.Ok
+ /// [`read()`]: trait.Read.html#tymethod.read
///
/// ```
/// use std::io;
@@ -811,16 +907,60 @@ pub trait Read {
}
}
+/// A type used to conditionally initialize buffers passed to `Read` methods.
+#[unstable(feature = "read_initializer", issue = "42788")]
+#[derive(Debug)]
+pub struct Initializer(bool);
+
+impl Initializer {
+ /// Returns a new `Initializer` which will zero out buffers.
+ #[unstable(feature = "read_initializer", issue = "42788")]
+ #[inline]
+ pub fn zeroing() -> Initializer {
+ Initializer(true)
+ }
+
+ /// Returns a new `Initializer` which will not zero out buffers.
+ ///
+ /// # Safety
+ ///
+ /// This may only be called by `Read`ers which guarantee that they will not
+ /// read from buffers passed to `Read` methods, and that the return value of
+ /// the method accurately reflects the number of bytes that have been
+ /// written to the head of the buffer.
+ #[unstable(feature = "read_initializer", issue = "42788")]
+ #[inline]
+ pub unsafe fn nop() -> Initializer {
+ Initializer(false)
+ }
+
+ /// Indicates if a buffer should be initialized.
+ #[unstable(feature = "read_initializer", issue = "42788")]
+ #[inline]
+ pub fn should_initialize(&self) -> bool {
+ self.0
+ }
+
+ /// Initializes a buffer if necessary.
+ #[unstable(feature = "read_initializer", issue = "42788")]
+ #[inline]
+ pub fn initialize(&self, buf: &mut [u8]) {
+ if self.should_initialize() {
+ unsafe { ptr::write_bytes(buf.as_mut_ptr(), 0, buf.len()) }
+ }
+ }
+}
+
/// A trait for objects which are byte-oriented sinks.
///
/// Implementors of the `Write` trait are sometimes called 'writers'.
///
-/// Writers are defined by two required methods, [`write()`] and [`flush()`]:
+/// Writers are defined by two required methods, [`write`] and [`flush`]:
///
-/// * The [`write()`] method will attempt to write some data into the object,
+/// * 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
+/// * 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'.
///
@@ -828,8 +968,8 @@ pub trait Read {
/// throughout [`std::io`] take and provide types which implement the `Write`
/// trait.
///
-/// [`write()`]: #tymethod.write
-/// [`flush()`]: #tymethod.flush
+/// [`write`]: #tymethod.write
+/// [`flush`]: #tymethod.flush
/// [`std::io`]: index.html
///
/// # Examples
@@ -846,6 +986,7 @@ pub trait Read {
/// # }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+#[doc(spotlight)]
pub trait Write {
/// Write a buffer into this object, returning how many bytes were written.
///
@@ -856,9 +997,9 @@ pub trait Write {
///
/// Calls to `write` are not guaranteed to block waiting for data to be
/// written, and a write which would otherwise block can be indicated through
- /// an `Err` variant.
+ /// an [`Err`] variant.
///
- /// If the return value is `Ok(n)` then it must be guaranteed that
+ /// 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.
@@ -872,6 +1013,13 @@ pub trait Write {
/// It is **not** considered an error if the entire buffer could not be
/// written to this writer.
///
+ /// An error of the [`ErrorKind::Interrupted`] kind is non-fatal and the
+ /// write operation should be retried if there is nothing else to do.
+ ///
+ /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+ /// [`Ok(n)`]: ../../std/result/enum.Result.html#variant.Ok
+ /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+ ///
/// # Examples
///
/// ```
@@ -881,6 +1029,7 @@ pub trait Write {
/// # fn foo() -> std::io::Result<()> {
/// let mut buffer = File::create("foo.txt")?;
///
+ /// // Writes some prefix of the byte string, not necessarily all of it.
/// buffer.write(b"some bytes")?;
/// # Ok(())
/// # }
@@ -916,14 +1065,20 @@ pub trait Write {
/// 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.
+ /// This method will continuously call [`write`] until there is no more data
+ /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is
+ /// returned. This method will not return until the entire buffer has been
+ /// successfully written or such an error occurs. The first error that is
+ /// not of [`ErrorKind::Interrupted`] kind generated from this method will be
+ /// returned.
///
/// # Errors
///
- /// This function will return the first error that `write` returns.
+ /// This function will return the first error of
+ /// non-[`ErrorKind::Interrupted`] kind that [`write`] returns.
+ ///
+ /// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
+ /// [`write`]: #tymethod.write
///
/// # Examples
///
@@ -1159,7 +1314,7 @@ fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>)
///
/// For example, reading line-by-line is inefficient without using a buffer, so
/// if you want to read by line, you'll need `BufRead`, which includes a
-/// [`read_line()`] method as well as a [`lines()`] iterator.
+/// [`read_line`] method as well as a [`lines`] iterator.
///
/// # Examples
///
@@ -1183,8 +1338,8 @@ fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>)
///
/// [`BufReader`]: struct.BufReader.html
/// [`File`]: ../fs/struct.File.html
-/// [`read_line()`]: #method.read_line
-/// [`lines()`]: #method.lines
+/// [`read_line`]: #method.read_line
+/// [`lines`]: #method.lines
/// [`Read`]: trait.Read.html
///
/// ```
@@ -1209,13 +1364,13 @@ pub trait BufRead: Read {
/// Fills the internal buffer of this object, returning the buffer contents.
///
/// This function is a lower-level call. It needs to be paired with the
- /// [`consume()`] method to function properly. When calling this
+ /// [`consume`] method to function properly. When calling this
/// method, none of the contents will be "read" in the sense that later
- /// calling `read` may return the same contents. As such, [`consume()`] must
+ /// calling `read` may return the same contents. As such, [`consume`] must
/// be called with the number of bytes that are consumed from this buffer to
/// ensure that the bytes are never returned twice.
///
- /// [`consume()`]: #tymethod.consume
+ /// [`consume`]: #tymethod.consume
///
/// An empty buffer returned indicates that the stream has reached EOF.
///
@@ -1256,21 +1411,21 @@ pub trait BufRead: Read {
/// so they should no longer be returned in calls to `read`.
///
/// This function is a lower-level call. It needs to be paired with the
- /// [`fill_buf()`] method to function properly. This function does
+ /// [`fill_buf`] method to function properly. This function does
/// not perform any I/O, it simply informs this object that some amount of
- /// its buffer, returned from [`fill_buf()`], has been consumed and should
+ /// its buffer, returned from [`fill_buf`], has been consumed and should
/// no longer be returned. As such, this function may do odd things if
- /// [`fill_buf()`] isn't called before calling it.
+ /// [`fill_buf`] isn't called before calling it.
///
/// The `amt` must be `<=` the number of bytes in the buffer returned by
- /// [`fill_buf()`].
+ /// [`fill_buf`].
///
/// # Examples
///
- /// Since `consume()` is meant to be used with [`fill_buf()`],
+ /// Since `consume()` is meant to be used with [`fill_buf`],
/// that method's example includes an example of `consume()`.
///
- /// [`fill_buf()`]: #tymethod.fill_buf
+ /// [`fill_buf`]: #tymethod.fill_buf
#[stable(feature = "rust1", since = "1.0.0")]
fn consume(&mut self, amt: usize);
@@ -1282,36 +1437,52 @@ pub trait BufRead: Read {
///
/// If successful, this function will return the total number of bytes read.
///
+ /// An empty buffer returned indicates that the stream has reached EOF.
+ ///
/// # Errors
///
/// This function will ignore all instances of [`ErrorKind::Interrupted`] and
- /// will otherwise return any errors returned by [`fill_buf()`].
+ /// 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.
///
- /// # Examples
- ///
- /// A locked standard input implements `BufRead`. In this example, we'll
- /// read from standard input until we see an `a` byte.
- ///
- /// [`fill_buf()`]: #tymethod.fill_buf
+ /// [`fill_buf`]: #tymethod.fill_buf
/// [`ErrorKind::Interrupted`]: enum.ErrorKind.html#variant.Interrupted
///
- /// ```
- /// use std::io;
- /// use std::io::prelude::*;
+ /// # Examples
///
- /// fn foo() -> io::Result<()> {
- /// let stdin = io::stdin();
- /// let mut stdin = stdin.lock();
- /// let mut buffer = Vec::new();
+ /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In
+ /// this example, we use [`Cursor`] to read all the bytes in a byte slice
+ /// in hyphen delimited segments:
///
- /// stdin.read_until(b'a', &mut buffer)?;
+ /// [`Cursor`]: struct.Cursor.html
///
- /// println!("{:?}", buffer);
- /// # Ok(())
- /// # }
+ /// ```
+ /// use std::io::{self, BufRead};
+ ///
+ /// let mut cursor = io::Cursor::new(b"lorem-ipsum");
+ /// let mut buf = vec![];
+ ///
+ /// // cursor is at 'l'
+ /// let num_bytes = cursor.read_until(b'-', &mut buf)
+ /// .expect("reading from cursor won't fail");
+ /// assert_eq!(num_bytes, 6);
+ /// assert_eq!(buf, b"lorem-");
+ /// buf.clear();
+ ///
+ /// // cursor is at 'i'
+ /// let num_bytes = cursor.read_until(b'-', &mut buf)
+ /// .expect("reading from cursor won't fail");
+ /// assert_eq!(num_bytes, 5);
+ /// assert_eq!(buf, b"ipsum");
+ /// buf.clear();
+ ///
+ /// // cursor is at EOF
+ /// let num_bytes = cursor.read_until(b'-', &mut buf)
+ /// .expect("reading from cursor won't fail");
+ /// assert_eq!(num_bytes, 0);
+ /// assert_eq!(buf, b"");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> Result<usize> {
@@ -1328,37 +1499,47 @@ pub trait BufRead: Read {
///
/// If successful, this function will return the total number of bytes read.
///
+ /// An empty buffer returned indicates that the stream has reached EOF.
+ ///
/// # Errors
///
- /// This function has the same error semantics as [`read_until()`] and will
+ /// 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.
///
/// # Examples
///
- /// A locked standard input implements `BufRead`. In this example, we'll
- /// read all of the lines from standard input. If we were to do this in
- /// an actual project, the [`lines()`] method would be easier, of
- /// course.
+ /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In
+ /// this example, we use [`Cursor`] to read all the lines in a byte slice:
///
- /// [`lines()`]: #method.lines
- /// [`read_until()`]: #method.read_until
+ /// [`Cursor`]: struct.Cursor.html
///
/// ```
- /// use std::io;
- /// use std::io::prelude::*;
- ///
- /// let stdin = io::stdin();
- /// let mut stdin = stdin.lock();
- /// let mut buffer = String::new();
- ///
- /// while stdin.read_line(&mut buffer).unwrap() > 0 {
- /// // work with buffer
- /// println!("{:?}", buffer);
- ///
- /// buffer.clear();
- /// }
+ /// use std::io::{self, BufRead};
+ ///
+ /// let mut cursor = io::Cursor::new(b"foo\nbar");
+ /// let mut buf = String::new();
+ ///
+ /// // cursor is at 'f'
+ /// let num_bytes = cursor.read_line(&mut buf)
+ /// .expect("reading from cursor won't fail");
+ /// assert_eq!(num_bytes, 4);
+ /// assert_eq!(buf, "foo\n");
+ /// buf.clear();
+ ///
+ /// // cursor is at 'b'
+ /// let num_bytes = cursor.read_line(&mut buf)
+ /// .expect("reading from cursor won't fail");
+ /// assert_eq!(num_bytes, 3);
+ /// assert_eq!(buf, "bar");
+ /// buf.clear();
+ ///
+ /// // cursor is at EOF
+ /// let num_bytes = cursor.read_line(&mut buf)
+ /// .expect("reading from cursor won't fail");
+ /// assert_eq!(num_bytes, 0);
+ /// assert_eq!(buf, "");
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn read_line(&mut self, buf: &mut String) -> Result<usize> {
@@ -1375,27 +1556,31 @@ pub trait BufRead: Read {
/// [`io::Result`]`<`[`Vec<u8>`]`>`. Each vector returned will *not* have
/// the delimiter byte at the end.
///
- /// This function will yield errors whenever [`read_until()`] would have
+ /// This function will yield errors whenever [`read_until`] would have
/// also yielded an error.
///
+ /// [`io::Result`]: type.Result.html
+ /// [`Vec<u8>`]: ../vec/struct.Vec.html
+ /// [`read_until`]: #method.read_until
+ ///
/// # Examples
///
- /// A locked standard input implements `BufRead`. In this example, we'll
- /// read some input from standard input, splitting on commas.
+ /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In
+ /// this example, we use [`Cursor`] to iterate over all hyphen delimited
+ /// segments in a byte slice
///
- /// [`io::Result`]: type.Result.html
- /// [`Vec<u8>`]: ../vec/struct.Vec.html
- /// [`read_until()`]: #method.read_until
+ /// [`Cursor`]: struct.Cursor.html
///
/// ```
- /// use std::io;
- /// use std::io::prelude::*;
+ /// use std::io::{self, BufRead};
///
- /// let stdin = io::stdin();
+ /// let cursor = io::Cursor::new(b"lorem-ipsum-dolor");
///
- /// for content in stdin.lock().split(b',') {
- /// println!("{:?}", content.unwrap());
- /// }
+ /// let mut split_iter = cursor.split(b'-').map(|l| l.unwrap());
+ /// assert_eq!(split_iter.next(), Some(b"lorem".to_vec()));
+ /// assert_eq!(split_iter.next(), Some(b"ipsum".to_vec()));
+ /// assert_eq!(split_iter.next(), Some(b"dolor".to_vec()));
+ /// assert_eq!(split_iter.next(), None);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn split(self, byte: u8) -> Split<Self> where Self: Sized {
@@ -1413,24 +1598,29 @@ pub trait BufRead: Read {
///
/// # Examples
///
- /// A locked standard input implements `BufRead`:
+ /// [`std::io::Cursor`][`Cursor`] is a type that implements `BufRead`. In
+ /// this example, we use [`Cursor`] to iterate over all the lines in a byte
+ /// slice.
+ ///
+ /// [`Cursor`]: struct.Cursor.html
///
/// ```
- /// use std::io;
- /// use std::io::prelude::*;
+ /// use std::io::{self, BufRead};
///
- /// let stdin = io::stdin();
+ /// let cursor = io::Cursor::new(b"lorem\nipsum\r\ndolor");
///
- /// for line in stdin.lock().lines() {
- /// println!("{}", line.unwrap());
- /// }
+ /// let mut lines_iter = cursor.lines().map(|l| l.unwrap());
+ /// assert_eq!(lines_iter.next(), Some(String::from("lorem")));
+ /// assert_eq!(lines_iter.next(), Some(String::from("ipsum")));
+ /// assert_eq!(lines_iter.next(), Some(String::from("dolor")));
+ /// assert_eq!(lines_iter.next(), None);
/// ```
///
/// # Errors
///
- /// Each line of the iterator has the same error semantics as [`BufRead::read_line()`].
+ /// Each line of the iterator has the same error semantics as [`BufRead::read_line`].
///
- /// [`BufRead::read_line()`]: trait.BufRead.html#method.read_line
+ /// [`BufRead::read_line`]: trait.BufRead.html#method.read_line
#[stable(feature = "rust1", since = "1.0.0")]
fn lines(self) -> Lines<Self> where Self: Sized {
Lines { buf: self }
@@ -1439,10 +1629,10 @@ pub trait BufRead: Read {
/// Adaptor to chain together two readers.
///
-/// This struct is generally created by calling [`chain()`] on a reader.
-/// Please see the documentation of [`chain()`] for more details.
+/// This struct is generally created by calling [`chain`] on a reader.
+/// Please see the documentation of [`chain`] for more details.
///
-/// [`chain()`]: trait.Read.html#method.chain
+/// [`chain`]: trait.Read.html#method.chain
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Chain<T, U> {
first: T,
@@ -1450,6 +1640,81 @@ pub struct Chain<T, U> {
done_first: bool,
}
+impl<T, U> Chain<T, U> {
+ /// Consumes the `Chain`, returning the wrapped readers.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use std::io;
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// # fn foo() -> io::Result<()> {
+ /// let mut foo_file = File::open("foo.txt")?;
+ /// let mut bar_file = File::open("bar.txt")?;
+ ///
+ /// let chain = foo_file.chain(bar_file);
+ /// let (foo_file, bar_file) = chain.into_inner();
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "more_io_inner_methods", since = "1.20.0")]
+ pub fn into_inner(self) -> (T, U) {
+ (self.first, self.second)
+ }
+
+ /// Gets references to the underlying readers in this `Chain`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use std::io;
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// # fn foo() -> io::Result<()> {
+ /// let mut foo_file = File::open("foo.txt")?;
+ /// let mut bar_file = File::open("bar.txt")?;
+ ///
+ /// let chain = foo_file.chain(bar_file);
+ /// let (foo_file, bar_file) = chain.get_ref();
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "more_io_inner_methods", since = "1.20.0")]
+ pub fn get_ref(&self) -> (&T, &U) {
+ (&self.first, &self.second)
+ }
+
+ /// Gets mutable references to the underlying readers in this `Chain`.
+ ///
+ /// Care should be taken to avoid modifying the internal I/O state of the
+ /// underlying readers as doing so may corrupt the internal state of this
+ /// `Chain`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use std::io;
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// # fn foo() -> io::Result<()> {
+ /// let mut foo_file = File::open("foo.txt")?;
+ /// let mut bar_file = File::open("bar.txt")?;
+ ///
+ /// let mut chain = foo_file.chain(bar_file);
+ /// let (foo_file, bar_file) = chain.get_mut();
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "more_io_inner_methods", since = "1.20.0")]
+ pub fn get_mut(&mut self) -> (&mut T, &mut U) {
+ (&mut self.first, &mut self.second)
+ }
+}
+
#[stable(feature = "std_debug", since = "1.16.0")]
impl<T: fmt::Debug, U: fmt::Debug> fmt::Debug for Chain<T, U> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -1471,6 +1736,15 @@ impl<T: Read, U: Read> Read for Chain<T, U> {
}
self.second.read(buf)
}
+
+ unsafe fn initializer(&self) -> Initializer {
+ let initializer = self.first.initializer();
+ if initializer.should_initialize() {
+ initializer
+ } else {
+ self.second.initializer()
+ }
+ }
}
#[stable(feature = "chain_bufread", since = "1.9.0")]
@@ -1496,10 +1770,10 @@ impl<T: BufRead, U: BufRead> BufRead for Chain<T, U> {
/// Reader adaptor which limits the bytes read from an underlying reader.
///
-/// This struct is generally created by calling [`take()`] on a reader.
-/// Please see the documentation of [`take()`] for more details.
+/// This struct is generally created by calling [`take`] on a reader.
+/// Please see the documentation of [`take`] for more details.
///
-/// [`take()`]: trait.Read.html#method.take
+/// [`take`]: trait.Read.html#method.take
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug)]
pub struct Take<T> {
@@ -1538,6 +1812,35 @@ impl<T> Take<T> {
#[stable(feature = "rust1", since = "1.0.0")]
pub fn limit(&self) -> u64 { self.limit }
+ /// Sets the number of bytes that can be read before this instance will
+ /// return EOF. This is the same as constructing a new `Take` instance, so
+ /// the amount of bytes read and the previous limit value don't matter when
+ /// calling this method.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(take_set_limit)]
+ /// use std::io;
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// # fn foo() -> io::Result<()> {
+ /// let f = File::open("foo.txt")?;
+ ///
+ /// // read at most five bytes
+ /// let mut handle = f.take(5);
+ /// handle.set_limit(10);
+ ///
+ /// assert_eq!(handle.limit(), 10);
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[unstable(feature = "take_set_limit", issue = "42781")]
+ pub fn set_limit(&mut self, limit: u64) {
+ self.limit = limit;
+ }
+
/// Consumes the `Take`, returning the wrapped reader.
///
/// # Examples
@@ -1562,6 +1865,60 @@ impl<T> Take<T> {
pub fn into_inner(self) -> T {
self.inner
}
+
+ /// Gets a reference to the underlying reader.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io;
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// # fn foo() -> io::Result<()> {
+ /// let mut file = File::open("foo.txt")?;
+ ///
+ /// let mut buffer = [0; 5];
+ /// let mut handle = file.take(5);
+ /// handle.read(&mut buffer)?;
+ ///
+ /// let file = handle.get_ref();
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "more_io_inner_methods", since = "1.20.0")]
+ pub fn get_ref(&self) -> &T {
+ &self.inner
+ }
+
+ /// Gets a mutable reference to the underlying reader.
+ ///
+ /// Care should be taken to avoid modifying the internal I/O state of the
+ /// underlying reader as doing so may corrupt the internal limit of this
+ /// `Take`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::io;
+ /// use std::io::prelude::*;
+ /// use std::fs::File;
+ ///
+ /// # fn foo() -> io::Result<()> {
+ /// let mut file = File::open("foo.txt")?;
+ ///
+ /// let mut buffer = [0; 5];
+ /// let mut handle = file.take(5);
+ /// handle.read(&mut buffer)?;
+ ///
+ /// let file = handle.get_mut();
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[stable(feature = "more_io_inner_methods", since = "1.20.0")]
+ pub fn get_mut(&mut self) -> &mut T {
+ &mut self.inner
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1577,6 +1934,10 @@ impl<T: Read> Read for Take<T> {
self.limit -= n as u64;
Ok(n)
}
+
+ unsafe fn initializer(&self) -> Initializer {
+ self.inner.initializer()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1614,10 +1975,10 @@ fn read_one_byte(reader: &mut Read) -> Option<Result<u8>> {
/// An iterator over `u8` values of a reader.
///
-/// This struct is generally created by calling [`bytes()`] on a reader.
-/// Please see the documentation of [`bytes()`] for more details.
+/// This struct is generally created by calling [`bytes`] on a reader.
+/// Please see the documentation of [`bytes`] for more details.
///
-/// [`bytes()`]: trait.Read.html#method.bytes
+/// [`bytes`]: trait.Read.html#method.bytes
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug)]
pub struct Bytes<R> {
@@ -1635,7 +1996,7 @@ impl<R: Read> Iterator for Bytes<R> {
/// An iterator over the `char`s of a reader.
///
-/// This struct is generally created by calling [`chars()`][chars] on a reader.
+/// This struct is generally created by calling [`chars`][chars] on a reader.
/// Please see the documentation of `chars()` for more details.
///
/// [chars]: trait.Read.html#method.chars
@@ -1666,10 +2027,9 @@ impl<R: Read> Iterator for Chars<R> {
type Item = result::Result<char, CharsError>;
fn next(&mut self) -> Option<result::Result<char, CharsError>> {
- let first_byte = match read_one_byte(&mut self.inner) {
- None => return None,
- Some(Ok(b)) => b,
- Some(Err(e)) => return Some(Err(CharsError::Other(e))),
+ let first_byte = match read_one_byte(&mut self.inner)? {
+ Ok(b) => b,
+ 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)) }
@@ -1726,7 +2086,7 @@ impl fmt::Display for CharsError {
/// An iterator over the contents of an instance of `BufRead` split on a
/// particular byte.
///
-/// This struct is generally created by calling [`split()`][split] on a
+/// This struct is generally created by calling [`split`][split] on a
/// `BufRead`. Please see the documentation of `split()` for more details.
///
/// [split]: trait.BufRead.html#method.split
@@ -1758,7 +2118,7 @@ impl<B: BufRead> Iterator for Split<B> {
/// An iterator over the lines of an instance of `BufRead`.
///
-/// This struct is generally created by calling [`lines()`][lines] on a
+/// This struct is generally created by calling [`lines`][lines] on a
/// `BufRead`. Please see the documentation of `lines()` for more details.
///
/// [lines]: trait.BufRead.html#method.lines
diff --git a/ctr-std/src/io/stdio.rs b/ctr-std/src/io/stdio.rs
index e16e801..831688b 100644
--- a/ctr-std/src/io/stdio.rs
+++ b/ctr-std/src/io/stdio.rs
@@ -13,11 +13,11 @@ use io::prelude::*;
use cell::RefCell;
use fmt;
use io::lazy::Lazy;
-use io::{self, BufReader, LineWriter};
+use io::{self, Initializer, BufReader, LineWriter};
use sync::{Arc, Mutex, MutexGuard};
use sys::stdio;
use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
-use thread::LocalKeyState;
+use thread::{LocalKey, LocalKeyState};
/// Stdout used by print! and println! macros
thread_local! {
@@ -75,8 +75,10 @@ fn stderr_raw() -> io::Result<StderrRaw> { stdio::Stderr::new().map(StderrRaw) }
impl Read for StdinRaw {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
- fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
- self.0.read_to_end(buf)
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
}
}
impl Write for StdoutRaw {
@@ -116,19 +118,11 @@ impl<R: io::Read> io::Read for Maybe<R> {
Maybe::Fake => Ok(0)
}
}
- fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
- match *self {
- Maybe::Real(ref mut r) => handle_ebadf(r.read_to_end(buf), 0),
- Maybe::Fake => Ok(0)
- }
- }
}
fn handle_ebadf<T>(r: io::Result<T>, default: T) -> io::Result<T> {
- use sys::stdio::EBADF_ERR;
-
match r {
- Err(ref e) if e.raw_os_error() == Some(EBADF_ERR) => Ok(default),
+ Err(ref e) if stdio::is_ebadf(e) => Ok(default),
r => r
}
}
@@ -294,6 +288,10 @@ impl Read for Stdin {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.lock().read(buf)
}
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.lock().read_to_end(buf)
}
@@ -310,8 +308,9 @@ impl<'a> Read for StdinLock<'a> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.read(buf)
}
- fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
- self.inner.read_to_end(buf)
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
}
}
@@ -332,11 +331,11 @@ impl<'a> fmt::Debug for StdinLock<'a> {
///
/// Each handle shares a global buffer of data to be written to the standard
/// output stream. Access is also synchronized via a lock and explicit control
-/// over locking is available via the [`lock()`] method.
+/// over locking is available via the [`lock`] method.
///
/// Created by the [`io::stdout`] method.
///
-/// [`lock()`]: #method.lock
+/// [`lock`]: #method.lock
/// [`io::stdout`]: fn.stdout.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Stdout {
@@ -659,41 +658,56 @@ pub fn set_print(sink: Option<Box<Write + Send>>) -> Option<Box<Write + Send>> {
})
}
-#[unstable(feature = "print",
- reason = "implementation detail which may disappear or be replaced at any time",
- issue = "0")]
-#[doc(hidden)]
-pub fn _print(args: fmt::Arguments) {
- // As an implementation of the `println!` macro, we want to try our best to
- // not panic wherever possible and get the output somewhere. There are
- // currently two possible vectors for panics we take care of here:
- //
- // 1. If the TLS key for the local stdout has been destroyed, accessing it
- // would cause a panic. Note that we just lump in the uninitialized case
- // here for convenience, we're not trying to avoid a panic.
- // 2. If the local stdout is currently in use (e.g. we're in the middle of
- // already printing) then accessing again would cause a panic.
- //
- // If, however, the actual I/O causes an error, we do indeed panic.
- let result = match LOCAL_STDOUT.state() {
+/// Write `args` to output stream `local_s` if possible, `global_s`
+/// otherwise. `label` identifies the stream in a panic message.
+///
+/// This function is used to print error messages, so it takes extra
+/// care to avoid causing a panic when `local_stream` is unusable.
+/// For instance, if the TLS key for the local stream is uninitialized
+/// or already destroyed, or if the local stream is locked by another
+/// thread, it will just fall back to the global stream.
+///
+/// However, if the actual I/O causes an error, this function does panic.
+fn print_to<T>(args: fmt::Arguments,
+ local_s: &'static LocalKey<RefCell<Option<Box<Write+Send>>>>,
+ global_s: fn() -> T,
+ label: &str) where T: Write {
+ let result = match local_s.state() {
LocalKeyState::Uninitialized |
- LocalKeyState::Destroyed => stdout().write_fmt(args),
+ LocalKeyState::Destroyed => global_s().write_fmt(args),
LocalKeyState::Valid => {
- LOCAL_STDOUT.with(|s| {
+ local_s.with(|s| {
if let Ok(mut borrowed) = s.try_borrow_mut() {
if let Some(w) = borrowed.as_mut() {
return w.write_fmt(args);
}
}
- stdout().write_fmt(args)
+ global_s().write_fmt(args)
})
}
};
if let Err(e) = result {
- panic!("failed printing to stdout: {}", e);
+ panic!("failed printing to {}: {}", label, e);
}
}
+#[unstable(feature = "print_internals",
+ reason = "implementation detail which may disappear or be replaced at any time",
+ issue = "0")]
+#[doc(hidden)]
+pub fn _print(args: fmt::Arguments) {
+ print_to(args, &LOCAL_STDOUT, stdout, "stdout");
+}
+
+#[unstable(feature = "print_internals",
+ reason = "implementation detail which may disappear or be replaced at any time",
+ issue = "0")]
+#[doc(hidden)]
+pub fn _eprint(args: fmt::Arguments) {
+ use panicking::LOCAL_STDERR;
+ print_to(args, &LOCAL_STDERR, stderr, "stderr");
+}
+
#[cfg(test)]
mod tests {
use thread;
diff --git a/ctr-std/src/io/util.rs b/ctr-std/src/io/util.rs
index 2c68802..45d281e 100644
--- a/ctr-std/src/io/util.rs
+++ b/ctr-std/src/io/util.rs
@@ -10,7 +10,9 @@
#![allow(missing_copy_implementations)]
-use io::{self, Read, Write, ErrorKind, BufRead};
+use fmt;
+use io::{self, Read, Initializer, Write, ErrorKind, BufRead};
+use mem;
/// Copies the entire contents of a reader into a writer.
///
@@ -36,17 +38,23 @@ use io::{self, Read, Write, ErrorKind, BufRead};
/// let mut reader: &[u8] = b"hello";
/// let mut writer: Vec<u8> = vec![];
///
-/// try!(io::copy(&mut reader, &mut writer));
+/// io::copy(&mut reader, &mut writer)?;
///
-/// assert_eq!(reader, &writer[..]);
+/// assert_eq!(&b"hello"[..], &writer[..]);
/// # Ok(())
/// # }
+/// # foo().unwrap();
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> io::Result<u64>
where R: Read, W: Write
{
- let mut buf = [0; super::DEFAULT_BUF_SIZE];
+ let mut buf = unsafe {
+ let mut buf: [u8; super::DEFAULT_BUF_SIZE] = mem::uninitialized();
+ reader.initializer().initialize(&mut buf);
+ buf
+ };
+
let mut written = 0;
loop {
let len = match reader.read(&mut buf) {
@@ -62,16 +70,18 @@ pub fn copy<R: ?Sized, W: ?Sized>(reader: &mut R, writer: &mut W) -> io::Result<
/// A reader which is always at EOF.
///
-/// This struct is generally created by calling [`empty()`][empty]. Please see
-/// the documentation of `empty()` for more details.
+/// This struct is generally created by calling [`empty`]. Please see
+/// the documentation of [`empty()`][`empty`] for more details.
///
-/// [empty]: fn.empty.html
+/// [`empty`]: fn.empty.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Empty { _priv: () }
/// Constructs a new handle to an empty reader.
///
-/// All reads from the returned reader will return `Ok(0)`.
+/// All reads from the returned reader will return [`Ok`]`(0)`.
+///
+/// [`Ok`]: ../result/enum.Result.html#variant.Ok
///
/// # Examples
///
@@ -89,17 +99,32 @@ pub fn empty() -> Empty { Empty { _priv: () } }
#[stable(feature = "rust1", since = "1.0.0")]
impl Read for Empty {
+ #[inline]
fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> { Ok(0) }
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl BufRead for Empty {
+ #[inline]
fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(&[]) }
+ #[inline]
fn consume(&mut self, _n: usize) {}
}
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for Empty {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.pad("Empty { .. }")
+ }
+}
+
/// A reader which yields one byte over and over and over and over and over and...
///
-/// This struct is generally created by calling [`repeat()`][repeat]. Please
+/// This struct is generally created by calling [`repeat`][repeat]. Please
/// see the documentation of `repeat()` for more details.
///
/// [repeat]: fn.repeat.html
@@ -125,17 +150,30 @@ pub fn repeat(byte: u8) -> Repeat { Repeat { byte: byte } }
#[stable(feature = "rust1", since = "1.0.0")]
impl Read for Repeat {
+ #[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
for slot in &mut *buf {
*slot = self.byte;
}
Ok(buf.len())
}
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+}
+
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for Repeat {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.pad("Repeat { .. }")
+ }
}
/// A writer which will move data into the void.
///
-/// This struct is generally created by calling [`sink()`][sink]. Please
+/// This struct is generally created by calling [`sink`][sink]. Please
/// see the documentation of `sink()` for more details.
///
/// [sink]: fn.sink.html
@@ -161,10 +199,19 @@ pub fn sink() -> Sink { Sink { _priv: () } }
#[stable(feature = "rust1", since = "1.0.0")]
impl Write for Sink {
+ #[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { Ok(buf.len()) }
+ #[inline]
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
+#[stable(feature = "std_debug", since = "1.16.0")]
+impl fmt::Debug for Sink {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.pad("Sink { .. }")
+ }
+}
+
#[cfg(test)]
mod tests {
use io::prelude::*;