From d54bd9f29af67748b7ddf80a5cf285145949ddc2 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 11 Mar 2015 14:16:46 -0700 Subject: [PATCH] std: Stabilize the `io` module The new `std::io` module has had some time to bake now, and this commit stabilizes its functionality. There are still portions of the module which remain unstable, and below contains a summart of the actions taken. This commit also deprecates the entire contents of the `old_io` module in a blanket fashion. All APIs should now have a reasonable replacement in the new I/O modules. Stable APIs: * `std::io` (the name) * `std::io::prelude` (the name) * `Read` * `Read::read` * `Read::{read_to_end, read_to_string}` after being modified to return a `usize` for the number of bytes read. * `Write` * `Write::write` * `Write::{write_all, write_fmt}` * `BufRead` * `BufRead::{fill_buf, consume}` * `BufRead::{read_line, read_until}` after being modified to return a `usize` for the number of bytes read. * `BufReader` * `BufReader::{new, with_capacity}` * `BufReader::{get_ref, get_mut, into_inner}` * `{Read,BufRead} for BufReader` * `BufWriter` * `BufWriter::{new, with_capacity}` * `BufWriter::{get_ref, get_mut, into_inner}` * `Write for BufWriter` * `IntoInnerError` * `IntoInnerError::{error, into_inner}` * `{Error,Display} for IntoInnerError` * `LineWriter` * `LineWriter::{new, with_capacity}` - `with_capacity` was added * `LineWriter::{get_ref, get_mut, into_inner}` - `get_mut` was added) * `Write for LineWriter` * `BufStream` * `BufStream::{new, with_capacities}` * `BufStream::{get_ref, get_mut, into_inner}` * `{BufRead,Read,Write} for BufStream` * `stdin` * `Stdin` * `Stdin::lock` * `Stdin::read_line` - added method * `StdinLock` * `Read for Stdin` * `{Read,BufRead} for StdinLock` * `stdout` * `Stdout` * `Stdout::lock` * `StdoutLock` * `Write for Stdout` * `Write for StdoutLock` * `stderr` * `Stderr` * `Stderr::lock` * `StderrLock` * `Write for Stderr` * `Write for StderrLock` * `io::Result` * `io::Error` * `io::Error::last_os_error` * `{Display, Error} for Error` Unstable APIs: (reasons can be found in the commit itself) * `Write::flush` * `Seek` * `ErrorKind` * `Error::new` * `Error::from_os_error` * `Error::kind` Deprecated APIs * `Error::description` - available via the `Error` trait * `Error::detail` - available via the `Display` implementation * `thread::Builder::{stdout, stderr}` Changes in functionality: * `old_io::stdio::set_stderr` is now a noop as the infrastructure for printing backtraces has migrated to `std::io`. * The `ReadExt`, `WriteExt`, and `BufReadExt` extension traits were all removed by folding functionality into the corresponding trait. [breaking-change] --- src/libstd/io/buffered.rs | 67 ++++++++++++++++--- src/libstd/io/error.rs | 24 ++++++- src/libstd/io/impls.rs | 16 ++--- src/libstd/io/mod.rs | 136 ++++++++++++++++++++++---------------- src/libstd/io/prelude.rs | 4 +- src/libstd/io/stdio.rs | 34 ++++++++-- src/libstd/old_io/mod.rs | 3 + src/libstd/thread.rs | 33 +++------ 8 files changed, 212 insertions(+), 105 deletions(-) diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 3603f127504..fb7af1d821d 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -16,8 +16,7 @@ use io::prelude::*; use cmp; -use error::Error as StdError; -use error::FromError; +use error::{self, FromError}; use fmt; use io::{self, Cursor, DEFAULT_BUF_SIZE, Error, ErrorKind}; use ptr; @@ -28,6 +27,7 @@ /// 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. +#[stable(feature = "rust1", since = "1.0.0")] pub struct BufReader { inner: R, buf: Cursor>, @@ -35,11 +35,13 @@ pub struct BufReader { impl BufReader { /// Creates a new `BufReader` with a default buffer capacity + #[stable(feature = "rust1", since = "1.0.0")] pub fn new(inner: R) -> BufReader { BufReader::with_capacity(DEFAULT_BUF_SIZE, inner) } /// Creates a new `BufReader` with the specified buffer capacity + #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(cap: usize, inner: R) -> BufReader { BufReader { inner: inner, @@ -48,6 +50,7 @@ pub fn with_capacity(cap: usize, inner: R) -> BufReader { } /// Gets a reference to the underlying reader. + #[stable(feature = "rust1", since = "1.0.0")] pub fn get_ref(&self) -> &R { &self.inner } /// Gets a mutable reference to the underlying reader. @@ -55,14 +58,17 @@ pub fn get_ref(&self) -> &R { &self.inner } /// # Warning /// /// It is inadvisable to directly read from the underlying reader. + #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut R { &mut self.inner } /// Unwraps this `BufReader`, returning the underlying reader. /// /// Note that any leftover data in the internal buffer is lost. + #[stable(feature = "rust1", since = "1.0.0")] pub fn into_inner(self) -> R { self.inner } } +#[stable(feature = "rust1", since = "1.0.0")] impl Read for BufReader { fn read(&mut self, buf: &mut [u8]) -> io::Result { // If we don't have any buffered data and we're doing a massive read @@ -77,6 +83,7 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result { } } +#[stable(feature = "rust1", since = "1.0.0")] impl BufRead for BufReader { fn fill_buf(&mut self) -> io::Result<&[u8]> { // If we've reached the end of our internal buffer then we need to fetch @@ -112,6 +119,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { /// underlying `Write` in large, infrequent batches. /// /// This writer will be flushed when it is dropped. +#[stable(feature = "rust1", since = "1.0.0")] pub struct BufWriter { inner: Option, buf: Vec, @@ -120,15 +128,18 @@ pub struct BufWriter { /// An error returned by `into_inner` which indicates whether a flush error /// happened or not. #[derive(Debug)] +#[stable(feature = "rust1", since = "1.0.0")] pub struct IntoInnerError(W, Error); impl BufWriter { /// Creates a new `BufWriter` with a default buffer capacity + #[stable(feature = "rust1", since = "1.0.0")] pub fn new(inner: W) -> BufWriter { BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner) } /// Creates a new `BufWriter` with the specified buffer capacity + #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(cap: usize, inner: W) -> BufWriter { BufWriter { inner: Some(inner), @@ -165,6 +176,7 @@ fn flush_buf(&mut self) -> io::Result<()> { } /// Gets a reference to the underlying writer. + #[stable(feature = "rust1", since = "1.0.0")] pub fn get_ref(&self) -> &W { self.inner.as_ref().unwrap() } /// Gets a mutable reference to the underlying write. @@ -172,11 +184,13 @@ pub fn get_ref(&self) -> &W { self.inner.as_ref().unwrap() } /// # Warning /// /// It is inadvisable to directly read from the underlying writer. + #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut W { self.inner.as_mut().unwrap() } /// Unwraps this `BufWriter`, returning the underlying writer. /// /// The buffer is flushed before returning the writer. + #[stable(feature = "rust1", since = "1.0.0")] pub fn into_inner(mut self) -> Result>> { match self.flush_buf() { Err(e) => Err(IntoInnerError(self, e)), @@ -185,6 +199,7 @@ pub fn into_inner(mut self) -> Result>> { } } +#[stable(feature = "rust1", since = "1.0.0")] impl Write for BufWriter { fn write(&mut self, buf: &[u8]) -> io::Result { if self.buf.len() + buf.len() > self.buf.capacity() { @@ -224,23 +239,30 @@ impl IntoInnerError { /// Returns the error which caused the call to `into_inner` to fail. /// /// This error was returned when attempting to flush the internal buffer. + #[stable(feature = "rust1", since = "1.0.0")] pub fn error(&self) -> &Error { &self.1 } /// Returns the underlying `BufWriter` instance which generated the error. /// /// The returned object can be used to retry a flush or re-inspect the /// buffer. + #[stable(feature = "rust1", since = "1.0.0")] pub fn into_inner(self) -> W { self.0 } } +#[stable(feature = "rust1", since = "1.0.0")] impl FromError> for Error { fn from_error(iie: IntoInnerError) -> Error { iie.1 } } -impl StdError for IntoInnerError { - fn description(&self) -> &str { self.error().description() } +#[stable(feature = "rust1", since = "1.0.0")] +impl error::Error for IntoInnerError { + fn description(&self) -> &str { + error::Error::description(self.error()) + } } +#[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for IntoInnerError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.error().fmt(f) @@ -251,26 +273,41 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { /// (`0x0a`, `'\n'`) is detected. /// /// This writer will be flushed when it is dropped. +#[stable(feature = "rust1", since = "1.0.0")] pub struct LineWriter { inner: BufWriter, } impl LineWriter { /// Creates a new `LineWriter` + #[stable(feature = "rust1", since = "1.0.0")] pub fn new(inner: W) -> LineWriter { // Lines typically aren't that long, don't use a giant buffer - LineWriter { inner: BufWriter::with_capacity(1024, inner) } + LineWriter::with_capacity(1024, inner) + } + + /// Creates a new `LineWriter` with a specified capacity for the internal + /// buffer. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn with_capacity(cap: usize, inner: W) -> LineWriter { + LineWriter { inner: BufWriter::with_capacity(cap, inner) } } /// Gets a reference to the underlying writer. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_ref(&self) -> &W { self.inner.get_ref() } + + /// Gets a mutable reference to the underlying writer. /// - /// This type does not expose the ability to get a mutable reference to the - /// underlying reader because that could possibly corrupt the buffer. - pub fn get_ref<'a>(&'a self) -> &'a W { self.inner.get_ref() } + /// Caution must be taken when calling methods on the mutable reference + /// returned as extra writes could corrupt the output stream. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_mut(&mut self) -> &mut W { self.inner.get_mut() } /// Unwraps this `LineWriter`, returning the underlying writer. /// /// The internal buffer is flushed before returning the writer. + #[stable(feature = "rust1", since = "1.0.0")] pub fn into_inner(self) -> Result>> { self.inner.into_inner().map_err(|IntoInnerError(buf, e)| { IntoInnerError(LineWriter { inner: buf }, e) @@ -278,6 +315,7 @@ pub fn into_inner(self) -> Result>> { } } +#[stable(feature = "rust1", since = "1.0.0")] impl Write for LineWriter { fn write(&mut self, buf: &[u8]) -> io::Result { match buf.rposition_elem(&b'\n') { @@ -320,12 +358,13 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result { /// Wraps a Stream and buffers input and output to and from it. /// -/// It can be excessively inefficient to work directly with a `Stream`. For +/// It can be excessively inefficient to work directly with a `Read+Write`. For /// example, every call to `read` or `write` on `TcpStream` results in a system /// call. A `BufStream` keeps in memory buffers of data, making large, -/// infrequent calls to `read` and `write` on the underlying `Stream`. +/// infrequent calls to `read` and `write` on the underlying `Read+Write`. /// /// The output half will be flushed when this stream is dropped. +#[stable(feature = "rust1", since = "1.0.0")] pub struct BufStream { inner: BufReader> } @@ -333,6 +372,7 @@ pub struct BufStream { impl BufStream { /// Creates a new buffered stream with explicitly listed capacities for the /// reader/writer buffer. + #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacities(reader_cap: usize, writer_cap: usize, inner: S) -> BufStream { let writer = BufWriter::with_capacity(writer_cap, inner); @@ -343,11 +383,13 @@ pub fn with_capacities(reader_cap: usize, writer_cap: usize, inner: S) /// Creates a new buffered stream with the default reader/writer buffer /// capacities. + #[stable(feature = "rust1", since = "1.0.0")] pub fn new(inner: S) -> BufStream { BufStream::with_capacities(DEFAULT_BUF_SIZE, DEFAULT_BUF_SIZE, inner) } /// Gets a reference to the underlying stream. + #[stable(feature = "rust1", since = "1.0.0")] pub fn get_ref(&self) -> &S { let InternalBufWriter(ref w) = self.inner.inner; w.get_ref() @@ -359,6 +401,7 @@ pub fn get_ref(&self) -> &S { /// /// It is inadvisable to read directly from or write directly to the /// underlying stream. + #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut S { let InternalBufWriter(ref mut w) = self.inner.inner; w.get_mut() @@ -368,6 +411,7 @@ pub fn get_mut(&mut self) -> &mut S { /// /// The internal buffer is flushed before returning the stream. Any leftover /// data in the read buffer is lost. + #[stable(feature = "rust1", since = "1.0.0")] pub fn into_inner(self) -> Result>> { let BufReader { inner: InternalBufWriter(w), buf } = self.inner; w.into_inner().map_err(|IntoInnerError(w, e)| { @@ -378,17 +422,20 @@ pub fn into_inner(self) -> Result>> { } } +#[stable(feature = "rust1", since = "1.0.0")] impl BufRead for BufStream { fn fill_buf(&mut self) -> io::Result<&[u8]> { self.inner.fill_buf() } fn consume(&mut self, amt: uint) { self.inner.consume(amt) } } +#[stable(feature = "rust1", since = "1.0.0")] impl Read for BufStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.inner.read(buf) } } +#[stable(feature = "rust1", since = "1.0.0")] impl Write for BufStream { fn write(&mut self, buf: &[u8]) -> io::Result { self.inner.inner.get_mut().write(buf) diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index 9f3cd8c8b15..530c6728107 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -10,7 +10,7 @@ use boxed::Box; use clone::Clone; -use error::Error as StdError; +use error; use fmt; use option::Option::{self, Some, None}; use result; @@ -22,6 +22,7 @@ /// /// This typedef is generally used to avoid writing out `io::Error` directly and /// is otherwise a direct mapping to `std::result::Result`. +#[stable(feature = "rust1", since = "1.0.0")] pub type Result = result::Result; /// The error type for I/O operations of the `Read`, `Write`, `Seek`, and @@ -31,6 +32,7 @@ /// `Error` can be created with crafted error messages and a particular value of /// `ErrorKind`. #[derive(PartialEq, Eq, Clone, Debug)] +#[stable(feature = "rust1", since = "1.0.0")] pub struct Error { repr: Repr, } @@ -50,6 +52,10 @@ struct Custom { /// A list specifying general categories of I/O error. #[derive(Copy, PartialEq, Eq, Clone, Debug)] +#[unstable(feature = "io", + reason = "the interaction between OS error codes and how they map to \ + these names (as well as the names themselves) has not \ + been thoroughly thought out")] pub enum ErrorKind { /// The file was not found. FileNotFound, @@ -96,6 +102,9 @@ pub enum ErrorKind { impl Error { /// Creates a new custom error from a specified kind/description/detail. + #[unstable(feature = "io", reason = "the exact makeup of an Error may + change to include `Box` for \ + example")] pub fn new(kind: ErrorKind, description: &'static str, detail: Option) -> Error { @@ -113,16 +122,20 @@ pub fn new(kind: ErrorKind, /// This function reads the value of `errno` for the target platform (e.g. /// `GetLastError` on Windows) and will return a corresponding instance of /// `Error` for the error code. + #[stable(feature = "rust1", since = "1.0.0")] pub fn last_os_error() -> Error { Error::from_os_error(sys::os::errno() as i32) } /// Creates a new instance of an `Error` from a particular OS error code. + #[unstable(feature = "io", + reason = "unclear whether this function is necessary")] pub fn from_os_error(code: i32) -> Error { Error { repr: Repr::Os(code) } } /// Return the corresponding `ErrorKind` for this error. + #[stable(feature = "rust1", since = "1.0.0")] pub fn kind(&self) -> ErrorKind { match self.repr { Repr::Os(code) => sys::decode_error_kind(code), @@ -131,6 +144,9 @@ pub fn kind(&self) -> ErrorKind { } /// Returns a short description for this error message + #[unstable(feature = "io")] + #[deprecated(since = "1.0.0", reason = "use the Error trait's description \ + method instead")] pub fn description(&self) -> &str { match self.repr { Repr::Os(..) => "os error", @@ -139,6 +155,8 @@ pub fn description(&self) -> &str { } /// Returns a detailed error message for this error (if one is available) + #[unstable(feature = "io")] + #[deprecated(since = "1.0.0", reason = "use the to_string() method instead")] pub fn detail(&self) -> Option { match self.repr { Repr::Os(code) => Some(sys::os::error_string(code)), @@ -147,6 +165,7 @@ pub fn detail(&self) -> Option { } } +#[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Error { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self.repr { @@ -173,7 +192,8 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { } } -impl StdError for Error { +#[stable(feature = "rust1", since = "1.0.0")] +impl error::Error for Error { fn description(&self) -> &str { match self.repr { Repr::Os(..) => "os error", diff --git a/src/libstd/io/impls.rs b/src/libstd/io/impls.rs index c968415d3ef..16298240acf 100644 --- a/src/libstd/io/impls.rs +++ b/src/libstd/io/impls.rs @@ -27,10 +27,10 @@ impl<'a, R: Read + ?Sized> Read for &'a mut R { fn read(&mut self, buf: &mut [u8]) -> io::Result { (**self).read(buf) } - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result<()> { + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { (**self).read_to_end(buf) } - fn read_to_string(&mut self, buf: &mut String) -> io::Result<()> { + fn read_to_string(&mut self, buf: &mut String) -> io::Result { (**self).read_to_string(buf) } } @@ -53,10 +53,10 @@ fn seek(&mut self, pos: SeekFrom) -> io::Result { (**self).seek(pos) } impl<'a, B: BufRead + ?Sized> BufRead for &'a mut B { fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() } fn consume(&mut self, amt: usize) { (**self).consume(amt) } - fn read_until(&mut self, byte: u8, buf: &mut Vec) -> io::Result<()> { + fn read_until(&mut self, byte: u8, buf: &mut Vec) -> io::Result { (**self).read_until(byte, buf) } - fn read_line(&mut self, buf: &mut String) -> io::Result<()> { + fn read_line(&mut self, buf: &mut String) -> io::Result { (**self).read_line(buf) } } @@ -66,10 +66,10 @@ impl Read for Box { fn read(&mut self, buf: &mut [u8]) -> io::Result { (**self).read(buf) } - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result<()> { + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { (**self).read_to_end(buf) } - fn read_to_string(&mut self, buf: &mut String) -> io::Result<()> { + fn read_to_string(&mut self, buf: &mut String) -> io::Result { (**self).read_to_string(buf) } } @@ -92,10 +92,10 @@ fn seek(&mut self, pos: SeekFrom) -> io::Result { (**self).seek(pos) } impl BufRead for Box { fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() } fn consume(&mut self, amt: usize) { (**self).consume(amt) } - fn read_until(&mut self, byte: u8, buf: &mut Vec) -> io::Result<()> { + fn read_until(&mut self, byte: u8, buf: &mut Vec) -> io::Result { (**self).read_until(byte, buf) } - fn read_line(&mut self, buf: &mut String) -> io::Result<()> { + fn read_line(&mut self, buf: &mut String) -> io::Result { (**self).read_line(buf) } } diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 9137068076b..5500f8d6c75 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -14,13 +14,11 @@ //! > development. At this time it is still recommended to use the `old_io` //! > module while the details of this module shake out. -#![unstable(feature = "io", - reason = "this new I/O module is still under active development and \ - APIs are subject to tweaks fairly regularly")] +#![stable(feature = "rust1", since = "1.0.0")] use cmp; use unicode::str as core_str; -use error::Error as StdError; +use error as std_error; use fmt; use iter::Iterator; use marker::Sized; @@ -111,8 +109,8 @@ unsafe fn black_box(mut dummy: T) -> T { // 2. We're passing a raw buffer to the function `f`, and it is expected that // the function only *appends* bytes to the buffer. We'll get undefined // behavior if existing bytes are overwritten to have non-UTF-8 data. -fn append_to_string(buf: &mut String, f: F) -> Result<()> - where F: FnOnce(&mut Vec) -> Result<()> +fn append_to_string(buf: &mut String, f: F) -> Result + where F: FnOnce(&mut Vec) -> Result { struct Guard<'a> { s: &'a mut Vec, len: usize } #[unsafe_destructor] @@ -126,7 +124,7 @@ fn drop(&mut self) { let mut g = Guard { len: buf.len(), s: buf.as_mut_vec() }; let ret = f(g.s); if str::from_utf8(&g.s[g.len..]).is_err() { - ret.and_then(|()| { + ret.and_then(|_| { Err(Error::new(ErrorKind::InvalidInput, "stream did not contain valid UTF-8", None)) }) @@ -137,14 +135,15 @@ fn drop(&mut self) { } } -fn read_to_end(r: &mut R, buf: &mut Vec) -> Result<()> { +fn read_to_end(r: &mut R, buf: &mut Vec) -> Result { + let mut read = 0; loop { if buf.capacity() == buf.len() { buf.reserve(DEFAULT_BUF_SIZE); } match with_end_to_cap(buf, |b| r.read(b)) { - Ok(0) => return Ok(()), - Ok(_) => {} + Ok(0) => return Ok(read), + Ok(n) => read += n, Err(ref e) if e.kind() == ErrorKind::Interrupted => {} Err(e) => return Err(e), } @@ -159,6 +158,7 @@ fn read_to_end(r: &mut R, buf: &mut Vec) -> Result<()> { /// Readers are intended to be composable with one another. Many objects /// throughout the I/O and related libraries take and provide types which /// implement the `Read` trait. +#[stable(feature = "rust1", since = "1.0.0")] pub trait Read { /// Pull some bytes from this source into the specified buffer, returning /// how many bytes were read. @@ -187,6 +187,7 @@ pub trait Read { /// If this function encounters any form of I/O or other error, an error /// variant will be returned. If an error is returned then it must be /// guaranteed that no bytes were read. + #[stable(feature = "rust1", since = "1.0.0")] fn read(&mut self, buf: &mut [u8]) -> Result; /// Read all bytes until EOF in this source, placing them into `buf`. @@ -198,7 +199,8 @@ pub trait Read { /// 2. Returns an error which is not of the kind `ErrorKind::Interrupted`. /// /// Until one of these conditions is met the function will continuously - /// invoke `read` to append more data to `buf`. + /// invoke `read` to append more data to `buf`. If successful, this function + /// will return the total number of bytes read. /// /// # Errors /// @@ -209,19 +211,24 @@ pub trait Read { /// If any other read error is encountered then this function immediately /// returns. Any bytes which have already been read will be appended to /// `buf`. - fn read_to_end(&mut self, buf: &mut Vec) -> Result<()> { + #[stable(feature = "rust1", since = "1.0.0")] + fn read_to_end(&mut self, buf: &mut Vec) -> Result { read_to_end(self, buf) } /// Read all bytes until EOF in this source, placing them into `buf`. /// + /// If successful, this function returns the number of bytes which were read + /// and appended to `buf`. + /// /// # Errors /// /// If the data in this stream is *not* valid UTF-8 then an error is /// returned and `buf` is unchanged. /// /// See `read_to_end` for other error semantics. - fn read_to_string(&mut self, buf: &mut String) -> Result<()> { + #[stable(feature = "rust1", since = "1.0.0")] + fn read_to_string(&mut self, buf: &mut String) -> Result { // Note that we do *not* call `.read_to_end()` here. We are passing // `&mut Vec` (the raw contents of `buf`) into the `read_to_end` // method to fill it up. An arbitrary implementation could overwrite the @@ -233,18 +240,13 @@ fn read_to_string(&mut self, buf: &mut String) -> Result<()> { // know is guaranteed to only read data into the end of the buffer. append_to_string(buf, |b| read_to_end(self, b)) } -} -/// Extension methods for all instances of `Read`, typically imported through -/// `std::io::prelude::*`. -#[unstable(feature = "io", reason = "may merge into the Read trait")] -pub trait ReadExt: Read + Sized { /// Create a "by reference" adaptor for this instance of `Read`. /// /// The returned adaptor also implements `Read` and will simply borrow this /// current reader. #[stable(feature = "rust1", since = "1.0.0")] - fn by_ref(&mut self) -> &mut Self { self } + fn by_ref(&mut self) -> &mut Self where Self: Sized { self } /// Transform this `Read` instance to an `Iterator` over its bytes. /// @@ -253,7 +255,7 @@ fn by_ref(&mut self) -> &mut Self { self } /// `Err` otherwise for I/O errors. EOF is mapped to returning `None` from /// this iterator. #[stable(feature = "rust1", since = "1.0.0")] - fn bytes(self) -> Bytes { + fn bytes(self) -> Bytes where Self: Sized { Bytes { inner: self } } @@ -270,7 +272,7 @@ fn bytes(self) -> Bytes { #[unstable(feature = "io", reason = "the semantics of a partial read/write \ of where errors happen is currently \ unclear and may change")] - fn chars(self) -> Chars { + fn chars(self) -> Chars where Self: Sized { Chars { inner: self } } @@ -280,7 +282,7 @@ fn chars(self) -> Chars { /// until EOF is encountered. Afterwards the output is equivalent to the /// output of `next`. #[stable(feature = "rust1", since = "1.0.0")] - fn chain(self, next: R) -> Chain { + fn chain(self, next: R) -> Chain where Self: Sized { Chain { first: self, second: next, done_first: false } } @@ -291,7 +293,7 @@ fn chain(self, next: R) -> Chain { /// read errors will not count towards the number of bytes read and future /// calls to `read` may succeed. #[stable(feature = "rust1", since = "1.0.0")] - fn take(self, limit: u64) -> Take { + fn take(self, limit: u64) -> Take where Self: Sized { Take { inner: self, limit: limit } } @@ -304,13 +306,11 @@ fn take(self, limit: u64) -> Take { #[unstable(feature = "io", reason = "the semantics of a partial read/write \ of where errors happen is currently \ unclear and may change")] - fn tee(self, out: W) -> Tee { + fn tee(self, out: W) -> Tee where Self: Sized { Tee { reader: self, writer: out } } } -impl ReadExt for T {} - /// A trait for objects which are byte-oriented sinks. /// /// The `write` method will attempt to write some data into the object, @@ -322,6 +322,7 @@ impl ReadExt for T {} /// Writers are intended to be composable with one another. Many objects /// throughout the I/O and related libraries take and provide types which /// implement the `Write` trait. +#[stable(feature = "rust1", since = "1.0.0")] pub trait Write { /// Write a buffer into this object, returning how many bytes were written. /// @@ -347,6 +348,7 @@ pub trait Write { /// /// It is **not** considered an error if the entire buffer could not be /// written to this writer. + #[stable(feature = "rust1", since = "1.0.0")] fn write(&mut self, buf: &[u8]) -> Result; /// Flush this output stream, ensuring that all intermediately buffered @@ -356,6 +358,7 @@ pub trait Write { /// /// It is considered an error if not all bytes could be written due to /// I/O errors or EOF being reached. + #[unstable(feature = "io", reason = "waiting for RFC 950")] fn flush(&mut self) -> Result<()>; /// Attempts to write an entire buffer into this write. @@ -368,6 +371,7 @@ pub trait Write { /// # Errors /// /// This function will return the first error that `write` returns. + #[stable(feature = "rust1", since = "1.0.0")] fn write_all(&mut self, mut buf: &[u8]) -> Result<()> { while buf.len() > 0 { match self.write(buf) { @@ -396,6 +400,7 @@ fn write_all(&mut self, mut buf: &[u8]) -> Result<()> { /// # Errors /// /// This function will return any I/O error reported while formatting. + #[stable(feature = "rust1", since = "1.0.0")] fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<()> { // Create a shim which translates a Write to a fmt::Write and saves // off I/O errors. instead of discarding them @@ -422,18 +427,13 @@ fn write_str(&mut self, s: &str) -> fmt::Result { Err(..) => output.error } } -} -/// Extension methods for all instances of `Write`, typically imported through -/// `std::io::prelude::*`. -#[unstable(feature = "io", reason = "may merge into the Read trait")] -pub trait WriteExt: Write + Sized { /// Create a "by reference" adaptor for this instance of `Write`. /// /// The returned adaptor also implements `Write` and will simply borrow this /// current writer. #[stable(feature = "rust1", since = "1.0.0")] - fn by_ref(&mut self) -> &mut Self { self } + fn by_ref(&mut self) -> &mut Self where Self: Sized { self } /// Creates a new writer which will write all data to both this writer and /// another writer. @@ -446,19 +446,21 @@ fn by_ref(&mut self) -> &mut Self { self } #[unstable(feature = "io", reason = "the semantics of a partial read/write \ of where errors happen is currently \ unclear and may change")] - fn broadcast(self, other: W) -> Broadcast { + fn broadcast(self, other: W) -> Broadcast + where Self: Sized + { Broadcast { first: self, second: other } } } -#[stable(feature = "rust1", since = "1.0.0")] -impl WriteExt for T {} - /// An object implementing `Seek` internally has some form of cursor which can /// be moved within a stream of bytes. /// /// The stream typically has a fixed size, allowing seeking relative to either /// end or the current offset. +#[unstable(feature = "io", reason = "the central `seek` method may be split \ + into multiple methods instead of taking \ + an enum as an argument")] pub trait Seek { /// Seek to an offset, in bytes, in a stream /// @@ -479,6 +481,7 @@ pub trait Seek { /// Enumeration of possible methods to seek within an I/O object. #[derive(Copy, PartialEq, Eq, Clone, Debug)] +#[unstable(feature = "io", reason = "awaiting the stability of Seek")] pub enum SeekFrom { /// Set the offset to the provided number of bytes. Start(u64), @@ -499,7 +502,8 @@ pub enum SeekFrom { } fn read_until(r: &mut R, delim: u8, buf: &mut Vec) - -> Result<()> { + -> Result { + let mut read = 0; loop { let (done, used) = { let available = match r.fill_buf() { @@ -519,8 +523,9 @@ fn read_until(r: &mut R, delim: u8, buf: &mut Vec) } }; r.consume(used); + read += used; if done || used == 0 { - return Ok(()); + return Ok(read); } } } @@ -530,6 +535,7 @@ fn read_until(r: &mut R, delim: u8, buf: &mut Vec) /// /// This type extends the `Read` trait with a few methods that are not /// possible to reasonably implement with purely a read interface. +#[stable(feature = "rust1", since = "1.0.0")] pub trait BufRead: Read { /// Fills the internal buffer of this object, returning the buffer contents. /// @@ -546,10 +552,16 @@ pub trait BufRead: Read { /// /// This function will return an I/O error if the underlying reader was /// read, but returned an error. + #[stable(feature = "rust1", since = "1.0.0")] fn fill_buf(&mut self) -> Result<&[u8]>; /// Tells this buffer that `amt` bytes have been consumed from the buffer, /// so they should no longer be returned in calls to `read`. + /// + /// 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 no longer be returned. + #[stable(feature = "rust1", since = "1.0.0")] fn consume(&mut self, amt: usize); /// Read all bytes until the delimiter `byte` is reached. @@ -560,7 +572,8 @@ pub trait BufRead: Read { /// `buf`. /// /// If this buffered reader is currently at EOF, then this function will not - /// place any more bytes into `buf` and will return `Ok(())`. + /// place any more bytes into `buf` and will return `Ok(n)` where `n` is the + /// number of bytes which were read. /// /// # Errors /// @@ -569,7 +582,8 @@ pub trait BufRead: Read { /// /// If an I/O error is encountered then all bytes read so far will be /// present in `buf` and its length will have been adjusted appropriately. - fn read_until(&mut self, byte: u8, buf: &mut Vec) -> Result<()> { + #[stable(feature = "rust1", since = "1.0.0")] + fn read_until(&mut self, byte: u8, buf: &mut Vec) -> Result { read_until(self, byte, buf) } @@ -581,7 +595,8 @@ fn read_until(&mut self, byte: u8, buf: &mut Vec) -> Result<()> { /// found) will be appended to `buf`. /// /// If this reader is currently at EOF then this function will not modify - /// `buf` and will return `Ok(())`. + /// `buf` and will return `Ok(n)` where `n` is the number of bytes which + /// were read. /// /// # Errors /// @@ -589,17 +604,14 @@ fn read_until(&mut self, byte: u8, buf: &mut Vec) -> Result<()> { /// return an error if the read bytes are not valid UTF-8. If an I/O error /// is encountered then `buf` may contain some bytes already read in the /// event that all data read so far was valid UTF-8. - fn read_line(&mut self, buf: &mut String) -> Result<()> { + #[stable(feature = "rust1", since = "1.0.0")] + fn read_line(&mut self, buf: &mut String) -> Result { // Note that we are not calling the `.read_until` method here, but // rather our hardcoded implementation. For more details as to why, see // the comments in `read_to_end`. append_to_string(buf, |b| read_until(self, b'\n', b)) } -} -/// Extension methods for all instances of `BufRead`, typically imported through -/// `std::io::prelude::*`. -pub trait BufReadExt: BufRead + Sized { /// Returns an iterator over the contents of this reader split on the byte /// `byte`. /// @@ -611,7 +623,7 @@ pub trait BufReadExt: BufRead + Sized { /// yielded an error. #[unstable(feature = "io", reason = "may be renamed to not conflict with \ SliceExt::split")] - fn split(self, byte: u8) -> Split { + fn split(self, byte: u8) -> Split where Self: Sized { Split { buf: self, delim: byte } } @@ -624,22 +636,21 @@ fn split(self, byte: u8) -> Split { /// This function will yield errors whenever `read_string` would have also /// yielded an error. #[stable(feature = "rust1", since = "1.0.0")] - fn lines(self) -> Lines { + fn lines(self) -> Lines where Self: Sized { Lines { buf: self } } } -#[stable(feature = "rust1", since = "1.0.0")] -impl BufReadExt for T {} - /// A `Write` adaptor which will write data to multiple locations. /// /// For more information, see `WriteExt::broadcast`. +#[unstable(feature = "io", reason = "awaiting stability of WriteExt::broadcast")] pub struct Broadcast { first: T, second: U, } +#[unstable(feature = "io", reason = "awaiting stability of WriteExt::broadcast")] impl Write for Broadcast { fn write(&mut self, data: &[u8]) -> Result { let n = try!(self.first.write(data)); @@ -732,11 +743,13 @@ fn consume(&mut self, amt: usize) { /// An adaptor which will emit all read data to a specified writer as well. /// /// For more information see `ReadExt::tee` +#[unstable(feature = "io", reason = "awaiting stability of ReadExt::tee")] pub struct Tee { reader: R, writer: W, } +#[unstable(feature = "io", reason = "awaiting stability of ReadExt::tee")] impl Read for Tee { fn read(&mut self, buf: &mut [u8]) -> Result { let n = try!(self.reader.read(buf)); @@ -771,6 +784,7 @@ fn next(&mut self) -> Option> { /// A bridge from implementations of `Read` to an `Iterator` of `char`. /// /// See `ReadExt::chars` for more information. +#[unstable(feature = "io", reason = "awaiting stability of ReadExt::chars")] pub struct Chars { inner: R, } @@ -778,6 +792,7 @@ pub struct Chars { /// An enumeration of possible errors that can be generated from the `Chars` /// adapter. #[derive(PartialEq, Clone, Debug)] +#[unstable(feature = "io", reason = "awaiting stability of ReadExt::chars")] pub enum CharsError { /// Variant representing that the underlying stream was read successfully /// but it did not contain valid utf8 data. @@ -787,6 +802,7 @@ pub enum CharsError { Other(Error), } +#[unstable(feature = "io", reason = "awaiting stability of ReadExt::chars")] impl Iterator for Chars { type Item = result::Result; @@ -818,14 +834,15 @@ fn next(&mut self) -> Option> { } } -impl StdError for CharsError { +#[unstable(feature = "io", reason = "awaiting stability of ReadExt::chars")] +impl std_error::Error for CharsError { fn description(&self) -> &str { match *self { CharsError::NotUtf8 => "invalid utf8 encoding", - CharsError::Other(ref e) => e.description(), + CharsError::Other(ref e) => std_error::Error::description(e), } } - fn cause(&self) -> Option<&StdError> { + fn cause(&self) -> Option<&std_error::Error> { match *self { CharsError::NotUtf8 => None, CharsError::Other(ref e) => e.cause(), @@ -833,6 +850,7 @@ fn cause(&self) -> Option<&StdError> { } } +#[unstable(feature = "io", reason = "awaiting stability of ReadExt::chars")] impl fmt::Display for CharsError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { @@ -848,19 +866,21 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { /// particular byte. /// /// See `BufReadExt::split` for more information. +#[unstable(feature = "io", reason = "awaiting stability of BufReadExt::split")] pub struct Split { buf: B, delim: u8, } +#[unstable(feature = "io", reason = "awaiting stability of BufReadExt::split")] impl Iterator for Split { type Item = Result>; fn next(&mut self) -> Option>> { let mut buf = Vec::new(); match self.buf.read_until(self.delim, &mut buf) { - Ok(()) if buf.len() == 0 => None, - Ok(()) => { + Ok(0) => None, + Ok(_n) => { if buf[buf.len() - 1] == self.delim { buf.pop(); } @@ -887,8 +907,8 @@ impl Iterator for Lines { fn next(&mut self) -> Option> { let mut buf = String::new(); match self.buf.read_line(&mut buf) { - Ok(()) if buf.len() == 0 => None, - Ok(()) => { + Ok(0) => None, + Ok(_n) => { if buf.ends_with("\n") { buf.pop(); } diff --git a/src/libstd/io/prelude.rs b/src/libstd/io/prelude.rs index 637b1950985..6bf0ebd1a59 100644 --- a/src/libstd/io/prelude.rs +++ b/src/libstd/io/prelude.rs @@ -21,7 +21,9 @@ //! `Write`, `ReadExt`, and `WriteExt`. Structures and functions are not //! contained in this module. -pub use super::{Read, ReadExt, Write, WriteExt, BufRead, BufReadExt}; +#![stable(feature = "rust1", since = "1.0.0")] + +pub use super::{Read, Write, BufRead}; pub use fs::PathExt; // FIXME: pub use as `Seek` when the name isn't in the actual prelude any more diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 4027f741654..c8625a2765d 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -86,6 +86,7 @@ fn flush(&mut self) -> io::Result<()> { Ok(()) } /// /// This handle implements the `Read` trait, but beware that concurrent reads /// of `Stdin` must be executed with care. +#[stable(feature = "rust1", since = "1.0.0")] pub struct Stdin { inner: Arc>>, } @@ -94,6 +95,7 @@ pub struct Stdin { /// /// This handle implements both the `Read` and `BufRead` traits and is /// constructed via the `lock` method on `Stdin`. +#[stable(feature = "rust1", since = "1.0.0")] pub struct StdinLock<'a> { inner: MutexGuard<'a, BufReader>, } @@ -110,6 +112,7 @@ pub struct StdinLock<'a> { /// /// To avoid locking and buffering altogether, it is recommended to use the /// `stdin_raw` constructor. +#[stable(feature = "rust1", since = "1.0.0")] pub fn stdin() -> Stdin { static INSTANCE: Lazy>> = lazy_init!(stdin_init); return Stdin { @@ -136,30 +139,41 @@ impl Stdin { /// The lock is released when the returned lock goes out of scope. The /// returned guard also implements the `Read` and `BufRead` traits for /// accessing the underlying data. + #[stable(feature = "rust1", since = "1.0.0")] pub fn lock(&self) -> StdinLock { StdinLock { inner: self.inner.lock().unwrap() } } + + /// Locks this handle and reads a line of input into the specified buffer. + /// + /// For detailed semantics of this method, see the documentation on + /// `BufRead::read_line`. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn read_line(&mut self, buf: &mut String) -> io::Result { + self.lock().read_line(buf) + } } +#[stable(feature = "rust1", since = "1.0.0")] impl Read for Stdin { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.lock().read(buf) } - - fn read_to_end(&mut self, buf: &mut Vec) -> io::Result<()> { + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { self.lock().read_to_end(buf) } - - fn read_to_string(&mut self, buf: &mut String) -> io::Result<()> { + fn read_to_string(&mut self, buf: &mut String) -> io::Result { self.lock().read_to_string(buf) } } +#[stable(feature = "rust1", since = "1.0.0")] impl<'a> Read for StdinLock<'a> { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.inner.read(buf) } } +#[stable(feature = "rust1", since = "1.0.0")] impl<'a> BufRead for StdinLock<'a> { fn fill_buf(&mut self) -> io::Result<&[u8]> { self.inner.fill_buf() } fn consume(&mut self, n: usize) { self.inner.consume(n) } @@ -186,6 +200,7 @@ fn consume(&mut self, n: usize) { self.inner.consume(n) } /// 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. +#[stable(feature = "rust1", since = "1.0.0")] pub struct Stdout { // FIXME: this should be LineWriter or BufWriter depending on the state of // stdout (tty or not). Note that if this is not line buffered it @@ -197,6 +212,7 @@ pub struct Stdout { /// /// This handle implements the `Write` trait and is constructed via the `lock` /// method on `Stdout`. +#[stable(feature = "rust1", since = "1.0.0")] pub struct StdoutLock<'a> { inner: MutexGuard<'a, LineWriter>, } @@ -211,6 +227,7 @@ pub struct StdoutLock<'a> { /// /// To avoid locking and buffering altogether, it is recommended to use the /// `stdout_raw` constructor. +#[stable(feature = "rust1", since = "1.0.0")] pub fn stdout() -> Stdout { static INSTANCE: Lazy>> = lazy_init!(stdout_init); return Stdout { @@ -228,11 +245,13 @@ impl Stdout { /// /// The lock is released when the returned lock goes out of scope. The /// returned guard also implements the `Write` trait for writing data. + #[stable(feature = "rust1", since = "1.0.0")] pub fn lock(&self) -> StdoutLock { StdoutLock { inner: self.inner.lock().unwrap() } } } +#[stable(feature = "rust1", since = "1.0.0")] impl Write for Stdout { fn write(&mut self, buf: &[u8]) -> io::Result { self.lock().write(buf) @@ -247,6 +266,7 @@ fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> { self.lock().write_fmt(fmt) } } +#[stable(feature = "rust1", since = "1.0.0")] impl<'a> Write for StdoutLock<'a> { fn write(&mut self, buf: &[u8]) -> io::Result { self.inner.write(&buf[..cmp::min(buf.len(), OUT_MAX)]) @@ -257,6 +277,7 @@ fn flush(&mut self) -> io::Result<()> { self.inner.flush() } /// A handle to the standard error stream of a process. /// /// For more information, see `stderr` +#[stable(feature = "rust1", since = "1.0.0")] pub struct Stderr { inner: Arc>, } @@ -265,6 +286,7 @@ pub struct Stderr { /// /// This handle implements the `Write` trait and is constructed via the `lock` /// method on `Stderr`. +#[stable(feature = "rust1", since = "1.0.0")] pub struct StderrLock<'a> { inner: MutexGuard<'a, StderrRaw>, } @@ -278,6 +300,7 @@ pub struct StderrLock<'a> { /// /// To avoid locking altogether, it is recommended to use the `stderr_raw` /// constructor. +#[stable(feature = "rust1", since = "1.0.0")] pub fn stderr() -> Stderr { static INSTANCE: Lazy> = lazy_init!(stderr_init); return Stderr { @@ -295,11 +318,13 @@ impl Stderr { /// /// The lock is released when the returned lock goes out of scope. The /// returned guard also implements the `Write` trait for writing data. + #[stable(feature = "rust1", since = "1.0.0")] pub fn lock(&self) -> StderrLock { StderrLock { inner: self.inner.lock().unwrap() } } } +#[stable(feature = "rust1", since = "1.0.0")] impl Write for Stderr { fn write(&mut self, buf: &[u8]) -> io::Result { self.lock().write(buf) @@ -314,6 +339,7 @@ fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> { self.lock().write_fmt(fmt) } } +#[stable(feature = "rust1", since = "1.0.0")] impl<'a> Write for StderrLock<'a> { fn write(&mut self, buf: &[u8]) -> io::Result { self.inner.write(&buf[..cmp::min(buf.len(), OUT_MAX)]) diff --git a/src/libstd/old_io/mod.rs b/src/libstd/old_io/mod.rs index f71698fa725..9d438978f42 100644 --- a/src/libstd/old_io/mod.rs +++ b/src/libstd/old_io/mod.rs @@ -242,6 +242,9 @@ #![deny(unused_must_use)] #![allow(deprecated)] // seriously this is all deprecated #![allow(unused_imports)] +#![deprecated(since = "1.0.0", + reasons = "APIs have been replaced with new I/O modules such as \ + std::{io, fs, net, process}")] pub use self::SeekStyle::*; pub use self::FileMode::*; diff --git a/src/libstd/thread.rs b/src/libstd/thread.rs index 5c5f9f75fd9..dcf7a37b7a6 100644 --- a/src/libstd/thread.rs +++ b/src/libstd/thread.rs @@ -148,7 +148,6 @@ use fmt; use io; use marker::PhantomData; -use old_io::stdio; use rt::{self, unwind}; use sync::{Mutex, Condvar, Arc}; use thunk::Thunk; @@ -165,10 +164,6 @@ pub struct Builder { name: Option, // The size of the stack for the spawned thread stack_size: Option, - // Thread-local stdout - stdout: Option>, - // Thread-local stderr - stderr: Option>, } impl Builder { @@ -179,8 +174,6 @@ pub fn new() -> Builder { Builder { name: None, stack_size: None, - stdout: None, - stderr: None, } } @@ -202,16 +195,22 @@ pub fn stack_size(mut self, size: usize) -> Builder { /// Redirect thread-local stdout. #[unstable(feature = "std_misc", reason = "Will likely go away after proc removal")] - pub fn stdout(mut self, stdout: Box) -> Builder { - self.stdout = Some(stdout); + #[deprecated(since = "1.0.0", + reason = "the old I/O module is deprecated and this function \ + will be removed with no replacement")] + #[allow(deprecated)] + pub fn stdout(self, _stdout: Box) -> Builder { self } /// Redirect thread-local stderr. #[unstable(feature = "std_misc", reason = "Will likely go away after proc removal")] - pub fn stderr(mut self, stderr: Box) -> Builder { - self.stderr = Some(stderr); + #[deprecated(since = "1.0.0", + reason = "the old I/O module is deprecated and this function \ + will be removed with no replacement")] + #[allow(deprecated)] + pub fn stderr(self, _stderr: Box) -> Builder { self } @@ -259,7 +258,7 @@ pub fn scoped<'a, T, F>(self, f: F) -> io::Result> where } fn spawn_inner(self, f: Thunk<(), T>) -> io::Result> { - let Builder { name, stack_size, stdout, stderr } = self; + let Builder { name, stack_size } = self; let stack_size = stack_size.unwrap_or(rt::min_stack()); @@ -290,16 +289,6 @@ fn spawn_inner(self, f: Thunk<(), T>) -> io::Result> { } let mut output = None; - let f: Thunk<(), T> = if stdout.is_some() || stderr.is_some() { - Thunk::new(move || { - let _ = stdout.map(stdio::set_stdout); - let _ = stderr.map(stdio::set_stderr); - f.invoke(()) - }) - } else { - f - }; - let try_result = { let ptr = &mut output; -- 2.44.0