diff options
| author | Fenrir <[email protected]> | 2018-01-21 14:06:28 -0700 |
|---|---|---|
| committer | FenrirWolf <[email protected]> | 2018-01-21 19:16:33 -0700 |
| commit | 23be3f4885688e5e0011005e2295c75168854c0a (patch) | |
| tree | dd0850f9c73c489e114a761d5c0757f3dbec3a65 /ctr-std/src/io | |
| parent | Update CI for Rust nightly-2017-12-01 + other fixes (diff) | |
| download | ctru-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.rs | 281 | ||||
| -rw-r--r-- | ctr-std/src/io/cursor.rs | 197 | ||||
| -rw-r--r-- | ctr-std/src/io/error.rs | 81 | ||||
| -rw-r--r-- | ctr-std/src/io/impls.rs | 47 | ||||
| -rw-r--r-- | ctr-std/src/io/lazy.rs | 2 | ||||
| -rw-r--r-- | ctr-std/src/io/mod.rs | 708 | ||||
| -rw-r--r-- | ctr-std/src/io/stdio.rs | 90 | ||||
| -rw-r--r-- | ctr-std/src/io/util.rs | 67 |
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::*; |