X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Flibstd%2Fio%2Fstdio.rs;h=f55a825a1370a09431d979b861ac44a3f7dce3f3;hb=857035ade7577d23bac596eb43c34e6844ce0b74;hp=61ad9905771a406b328d8de4161f2157a038b4b4;hpb=7ed4660a51b048f8b166b298d1777544d3a0fd98;p=rust.git diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 61ad9905771..f55a825a137 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -11,6 +11,7 @@ use prelude::v1::*; use io::prelude::*; +use cell::RefCell; use cmp; use fmt; use io::lazy::Lazy; @@ -18,23 +19,30 @@ use sync::{Arc, Mutex, MutexGuard}; use sys::stdio; +/// Stdout used by print! and println! macros +thread_local! { + static LOCAL_STDOUT: RefCell>> = { + RefCell::new(None) + } +} + /// A handle to a raw instance of the standard input stream of this process. /// /// This handle is not synchronized or buffered in any fashion. Constructed via -/// the `std::io::stdin_raw` function. -pub struct StdinRaw(stdio::Stdin); +/// the `std::io::stdio::stdin_raw` function. +struct StdinRaw(stdio::Stdin); /// A handle to a raw instance of the standard output stream of this process. /// /// This handle is not synchronized or buffered in any fashion. Constructed via -/// the `std::io::stdout_raw` function. -pub struct StdoutRaw(stdio::Stdout); +/// the `std::io::stdio::stdout_raw` function. +struct StdoutRaw(stdio::Stdout); /// A handle to a raw instance of the standard output stream of this process. /// /// This handle is not synchronized or buffered in any fashion. Constructed via -/// the `std::io::stderr_raw` function. -pub struct StderrRaw(stdio::Stderr); +/// the `std::io::stdio::stderr_raw` function. +struct StderrRaw(stdio::Stderr); /// Construct a new raw handle to the standard input of this process. /// @@ -43,7 +51,7 @@ /// handles is **not** available to raw handles returned from this function. /// /// The returned handle has no external synchronization or buffering. -pub fn stdin_raw() -> StdinRaw { StdinRaw(stdio::Stdin::new()) } +fn stdin_raw() -> StdinRaw { StdinRaw(stdio::Stdin::new()) } /// Construct a new raw handle to the standard input stream of this process. /// @@ -54,7 +62,7 @@ pub fn stdin_raw() -> StdinRaw { StdinRaw(stdio::Stdin::new()) } /// /// The returned handle has no external synchronization or buffering layered on /// top. -pub fn stdout_raw() -> StdoutRaw { StdoutRaw(stdio::Stdout::new()) } +fn stdout_raw() -> StdoutRaw { StdoutRaw(stdio::Stdout::new()) } /// Construct a new raw handle to the standard input stream of this process. /// @@ -63,7 +71,7 @@ pub fn stdout_raw() -> StdoutRaw { StdoutRaw(stdio::Stdout::new()) } /// /// The returned handle has no external synchronization or buffering layered on /// top. -pub fn stderr_raw() -> StderrRaw { StderrRaw(stdio::Stderr::new()) } +fn stderr_raw() -> StderrRaw { StderrRaw(stdio::Stderr::new()) } impl Read for StdinRaw { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.0.read(buf) } @@ -86,6 +94,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 +103,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>, } @@ -107,9 +117,7 @@ pub struct StdinLock<'a> { /// The `Read` trait is implemented for the returned value but the `BufRead` /// trait is not due to the global nature of the standard input stream. The /// locked version, `StdinLock`, implements both `Read` and `BufRead`, however. -/// -/// 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,33 +144,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 { - // Flush stdout so that weird issues like a print!'d prompt not being - // shown until after the user hits enter. - drop(stdout().flush()); 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) } @@ -189,6 +205,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 @@ -200,6 +217,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,9 +229,7 @@ pub struct StdoutLock<'a> { /// provided via the `lock` method. /// /// The returned handle implements the `Write` trait. -/// -/// 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 { @@ -231,11 +247,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) @@ -250,6 +268,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)]) @@ -260,6 +279,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>, } @@ -268,6 +288,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,9 +299,7 @@ pub struct StderrLock<'a> { /// this function. No handles are buffered, however. /// /// The returned handle implements the `Write` trait. -/// -/// 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 { @@ -298,11 +317,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) @@ -317,9 +338,67 @@ 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)]) } fn flush(&mut self) -> io::Result<()> { self.inner.flush() } } + +/// Resets the task-local stderr handle to the specified writer +/// +/// This will replace the current task's stderr handle, returning the old +/// handle. All future calls to `panic!` and friends will emit their output to +/// this specified handle. +/// +/// Note that this does not need to be called for all new tasks; the default +/// output handle is to the process's stderr stream. +#[unstable(feature = "set_stdio", + reason = "this function may disappear completely or be replaced \ + with a more general mechanism")] +#[doc(hidden)] +pub fn set_panic(sink: Box) -> Option> { + use panicking::LOCAL_STDERR; + use mem; + LOCAL_STDERR.with(move |slot| { + mem::replace(&mut *slot.borrow_mut(), Some(sink)) + }).and_then(|mut s| { + let _ = s.flush(); + Some(s) + }) +} + +/// Resets the task-local stdout handle to the specified writer +/// +/// This will replace the current task's stdout handle, returning the old +/// handle. All future calls to `print!` and friends will emit their output to +/// this specified handle. +/// +/// Note that this does not need to be called for all new tasks; the default +/// output handle is to the process's stdout stream. +#[unstable(feature = "set_stdio", + reason = "this function may disappear completely or be replaced \ + with a more general mechanism")] +#[doc(hidden)] +pub fn set_print(sink: Box) -> Option> { + use mem; + LOCAL_STDOUT.with(move |slot| { + mem::replace(&mut *slot.borrow_mut(), Some(sink)) + }).and_then(|mut s| { + let _ = s.flush(); + Some(s) + }) +} + +#[unstable(feature = "print", + reason = "implementation detail which may disappear or be replaced at any time")] +#[doc(hidden)] +pub fn _print(args: fmt::Arguments) { + if let Err(e) = LOCAL_STDOUT.with(|s| match s.borrow_mut().as_mut() { + Some(w) => w.write_fmt(args), + None => stdout().write_fmt(args) + }) { + panic!("failed printing to stdout: {}", e); + } +}