From 02268cc8c5c5ee2cc9060bf97efa0730ec4344fc Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Tue, 11 Aug 2020 21:01:58 -0500 Subject: [PATCH 01/38] Update lib.rs --- library/std/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index f0487e0dff148..ffc06ae528f63 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -274,6 +274,7 @@ #![feature(global_asm)] #![feature(hash_raw_entry)] #![feature(hashmap_internals)] +#![feature(input)] #![feature(int_error_internals)] #![feature(int_error_matching)] #![feature(integer_atomics)] From 6fac729c8e159411059b4d0aa02f989252f07034 Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Tue, 11 Aug 2020 21:03:56 -0500 Subject: [PATCH 02/38] Update mod.rs --- library/std/src/io/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 9eb54c2cc0044..7d2ca3245f6dd 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -266,6 +266,8 @@ pub use self::buffered::{BufReader, BufWriter, LineWriter}; pub use self::cursor::Cursor; #[stable(feature = "rust1", since = "1.0.0")] pub use self::error::{Error, ErrorKind, Result}; +#[unstable(feature = "input", issue = "none")] +pub use self::stdio::input; #[stable(feature = "rust1", since = "1.0.0")] pub use self::stdio::{stderr, stdin, stdout, Stderr, Stdin, Stdout}; #[stable(feature = "rust1", since = "1.0.0")] From 843c2bf668ba10d3cd11a52e9218852db78f0c8c Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Tue, 11 Aug 2020 21:04:56 -0500 Subject: [PATCH 03/38] Update stdio.rs --- library/std/src/io/stdio.rs | 38 +++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 156f555be02d8..7d7b5e70b1024 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -903,6 +903,44 @@ impl fmt::Debug for StderrLock<'_> { } } +/// Prints the given `str` and reads a [`String`] from +/// [standard input](Stdin). The trailing newline is stripped. +/// Gives an error on EOF (end of file). +/// +/// # Note +/// +/// If you require more explicit control over capturing +/// user input, see the [`Stdin::read_line`] method. +/// +/// # Examples +/// +/// ```no_run +/// #![feature(input)] +/// use std::io; +/// +/// fn main() { +/// let name = io::input("Enter name: ").expect("input failed!"); +/// +/// println!("Your name is {}!", name); +/// } +/// ``` +#[unstable( + feature = "input", + reason = "this function may be replaced with a more general mechanism", + issue = "none" +)] +pub fn input(prompt: &str) -> Result { + let stdout = stdout(); + let mut lock = stdout.lock(); + lock.write_all(prompt.as_bytes())?; + lock.flush()?; + let mut input = String::new(); + match stdin().read_line(&mut input)? { + 0 => Err(Error::new(ErrorKind::UnexpectedEof, "input reached eof unexpectedly")), + _ => Ok(String::from(input.trim_end_matches(&['\n', '\r'][..]))), + } +} + /// Resets the thread-local stderr handle to the specified writer /// /// This will replace the current thread's stderr handle, returning the old From 6c42a620ba080d4d5d976b2a47e57d79a190c2dd Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Tue, 11 Aug 2020 21:09:34 -0500 Subject: [PATCH 04/38] Update stdio.rs --- library/std/src/io/stdio.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 7d7b5e70b1024..3dd209ab8ea55 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -5,7 +5,9 @@ use crate::io::prelude::*; use crate::cell::RefCell; use crate::fmt; use crate::io::lazy::Lazy; -use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter}; +use crate::io::{ + self, BufReader, Error, ErrorKind, Initializer, IoSlice, IoSliceMut, LineWriter, Result, Write, +}; use crate::sync::{Arc, Mutex, MutexGuard, Once}; use crate::sys::stdio; use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; From 0fc63d958aa206c4234085139d7c21c932f01568 Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Wed, 12 Aug 2020 20:55:33 -0500 Subject: [PATCH 05/38] Update library/std/src/io/stdio.rs Co-authored-by: Lukas Kalbertodt --- library/std/src/io/stdio.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 3dd209ab8ea55..4206217618bbc 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -920,10 +920,11 @@ impl fmt::Debug for StderrLock<'_> { /// #![feature(input)] /// use std::io; /// -/// fn main() { -/// let name = io::input("Enter name: ").expect("input failed!"); -/// +/// fn main() -> io::Result<()> { +/// let name = io::input("Enter name: ")?; /// println!("Your name is {}!", name); +/// +/// Ok(()) /// } /// ``` #[unstable( From 25dcd9730314ecfec97282918c2ab7031d011d16 Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Wed, 12 Aug 2020 20:57:00 -0500 Subject: [PATCH 06/38] Update stdio.rs --- library/std/src/io/stdio.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 4206217618bbc..8806d37e5cc36 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -917,7 +917,7 @@ impl fmt::Debug for StderrLock<'_> { /// # Examples /// /// ```no_run -/// #![feature(input)] +/// #![feature(io_input)] /// use std::io; /// /// fn main() -> io::Result<()> { @@ -928,7 +928,7 @@ impl fmt::Debug for StderrLock<'_> { /// } /// ``` #[unstable( - feature = "input", + feature = "io_input", reason = "this function may be replaced with a more general mechanism", issue = "none" )] From ebb35f1402ac82163c9636eba924637535a423ab Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Wed, 12 Aug 2020 20:57:28 -0500 Subject: [PATCH 07/38] Update mod.rs --- library/std/src/io/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 7d2ca3245f6dd..fed27bfb098fe 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -266,7 +266,7 @@ pub use self::buffered::{BufReader, BufWriter, LineWriter}; pub use self::cursor::Cursor; #[stable(feature = "rust1", since = "1.0.0")] pub use self::error::{Error, ErrorKind, Result}; -#[unstable(feature = "input", issue = "none")] +#[unstable(feature = "io_input", issue = "none")] pub use self::stdio::input; #[stable(feature = "rust1", since = "1.0.0")] pub use self::stdio::{stderr, stdin, stdout, Stderr, Stdin, Stdout}; From c601238f1fc8fd6fd2a82b86a8d8439585b85d0c Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Wed, 12 Aug 2020 20:59:23 -0500 Subject: [PATCH 08/38] Update lib.rs --- library/std/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index ffc06ae528f63..f0487e0dff148 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -274,7 +274,6 @@ #![feature(global_asm)] #![feature(hash_raw_entry)] #![feature(hashmap_internals)] -#![feature(input)] #![feature(int_error_internals)] #![feature(int_error_matching)] #![feature(integer_atomics)] From ac0a700a5bc42ec604aa31871a85dcb61b05c827 Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Wed, 12 Aug 2020 21:15:12 -0500 Subject: [PATCH 09/38] Update stdio.rs trailing whitespace --- library/std/src/io/stdio.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 8806d37e5cc36..ff1ec951a53f1 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -922,8 +922,9 @@ impl fmt::Debug for StderrLock<'_> { /// /// fn main() -> io::Result<()> { /// let name = io::input("Enter name: ")?; +/// /// println!("Your name is {}!", name); -/// +/// /// Ok(()) /// } /// ``` From 905716b4c0aff53f0d894769e92350a1cb612a51 Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Sun, 13 Sep 2020 00:01:42 -0500 Subject: [PATCH 10/38] Update stdio.rs add from str --- library/std/src/io/stdio.rs | 63 ++++++++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 11 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index ff1ec951a53f1..d16cc4a659f14 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -6,8 +6,9 @@ use crate::cell::RefCell; use crate::fmt; use crate::io::lazy::Lazy; use crate::io::{ - self, BufReader, Error, ErrorKind, Initializer, IoSlice, IoSliceMut, LineWriter, Result, Write, + self, BufReader, Error, Initializer, IoSlice, IoSliceMut, LineWriter, Result, Write, }; +use crate::str; use crate::sync::{Arc, Mutex, MutexGuard, Once}; use crate::sys::stdio; use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; @@ -905,6 +906,43 @@ impl fmt::Debug for StderrLock<'_> { } } +/// Similar to the [`prompt_line`] function, but does +/// not print a prompt. +/// +/// # Note +/// +/// If you require more explicit control over capturing +/// user input, see the [`Stdin::read_line`] method. +/// +/// # Examples +/// +/// ```no_run +/// #![feature(io_input)] +/// use std::io; +/// +/// fn main() -> io::Result<()> { +/// let name = io::read_line("Enter name: ")?; +/// +/// println!("Your name is {}!", name); +/// +/// Ok(()) +/// } +/// ``` +#[unstable( + feature = "io_input", + reason = "this function may be replaced with a more general mechanism", + issue = "none" +)] +pub fn read_line() -> Result::Err> +where + T: str::FromStr, + ::Err: fmt::Debug, +{ + let mut input = String::new(); + stdin().read_line(&mut input).expect("failed to read stdin"); + input.trim_end_matches(&['\n', '\r'][..]).parse::() +} + /// Prints the given `str` and reads a [`String`] from /// [standard input](Stdin). The trailing newline is stripped. /// Gives an error on EOF (end of file). @@ -917,11 +955,11 @@ impl fmt::Debug for StderrLock<'_> { /// # Examples /// /// ```no_run -/// #![feature(io_input)] +/// #![feature(io_input_prompt)] /// use std::io; /// /// fn main() -> io::Result<()> { -/// let name = io::input("Enter name: ")?; +/// let name = io::prompt_line("Enter name: ")?; /// /// println!("Your name is {}!", name); /// @@ -929,20 +967,23 @@ impl fmt::Debug for StderrLock<'_> { /// } /// ``` #[unstable( - feature = "io_input", + feature = "io_input_prompt", reason = "this function may be replaced with a more general mechanism", issue = "none" )] -pub fn input(prompt: &str) -> Result { +pub fn prompt_line(prompt: &str) -> Result::Err> +where + T: str::FromStr, + ::Err: fmt::Debug, +{ let stdout = stdout(); let mut lock = stdout.lock(); - lock.write_all(prompt.as_bytes())?; - lock.flush()?; + lock.write_all(prompt.as_bytes()) + .expect("failed to write whole buffer"); + lock.flush().expect("failed to flush stdout"); let mut input = String::new(); - match stdin().read_line(&mut input)? { - 0 => Err(Error::new(ErrorKind::UnexpectedEof, "input reached eof unexpectedly")), - _ => Ok(String::from(input.trim_end_matches(&['\n', '\r'][..]))), - } + stdin().read_line(&mut input).expect("failed to read stdin"); + input.trim_end_matches(&['\n', '\r'][..]).parse::() } /// Resets the thread-local stderr handle to the specified writer From 561f85f972ca9283e4fe4d94ebafb42f4d50ad72 Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Sun, 13 Sep 2020 00:02:42 -0500 Subject: [PATCH 11/38] Update mod.rs add extra func --- library/std/src/io/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index fed27bfb098fe..b0a042609fd3d 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -267,7 +267,9 @@ pub use self::cursor::Cursor; #[stable(feature = "rust1", since = "1.0.0")] pub use self::error::{Error, ErrorKind, Result}; #[unstable(feature = "io_input", issue = "none")] -pub use self::stdio::input; +pub use self::stdio::read_line; +#[unstable(feature = "io_input_prompt", issue = "none")] +pub use self::stdio::prompt_line; #[stable(feature = "rust1", since = "1.0.0")] pub use self::stdio::{stderr, stdin, stdout, Stderr, Stdin, Stdout}; #[stable(feature = "rust1", since = "1.0.0")] From e69e325f1a1d25eb96abba99351bec2055772f35 Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Sun, 13 Sep 2020 00:14:16 -0500 Subject: [PATCH 12/38] Update stdio.rs imports --- library/std/src/io/stdio.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index d16cc4a659f14..981130a8c1411 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -6,8 +6,9 @@ use crate::cell::RefCell; use crate::fmt; use crate::io::lazy::Lazy; use crate::io::{ - self, BufReader, Error, Initializer, IoSlice, IoSliceMut, LineWriter, Result, Write, + self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter, Result, Write, }; +use crate::result; use crate::str; use crate::sync::{Arc, Mutex, MutexGuard, Once}; use crate::sys::stdio; @@ -933,7 +934,7 @@ impl fmt::Debug for StderrLock<'_> { reason = "this function may be replaced with a more general mechanism", issue = "none" )] -pub fn read_line() -> Result::Err> +pub fn read_line() -> result::Result::Err> where T: str::FromStr, ::Err: fmt::Debug, @@ -971,7 +972,7 @@ where reason = "this function may be replaced with a more general mechanism", issue = "none" )] -pub fn prompt_line(prompt: &str) -> Result::Err> +pub fn prompt_line(prompt: &str) -> result::Result::Err> where T: str::FromStr, ::Err: fmt::Debug, From 03d3b6f365562a999d404a3152b51972298a9736 Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Sun, 13 Sep 2020 00:18:36 -0500 Subject: [PATCH 13/38] Update stdio.rs unused import --- library/std/src/io/stdio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 981130a8c1411..47392e53ee587 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -6,7 +6,7 @@ use crate::cell::RefCell; use crate::fmt; use crate::io::lazy::Lazy; use crate::io::{ - self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter, Result, Write, + self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter, Write, }; use crate::result; use crate::str; From 80c29644c3275ca5067398808be6c1980d6aff3c Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Sun, 13 Sep 2020 00:41:49 -0500 Subject: [PATCH 14/38] Update mod.rs format --- library/std/src/io/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index b0a042609fd3d..f803f6dcfb204 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -266,10 +266,10 @@ pub use self::buffered::{BufReader, BufWriter, LineWriter}; pub use self::cursor::Cursor; #[stable(feature = "rust1", since = "1.0.0")] pub use self::error::{Error, ErrorKind, Result}; -#[unstable(feature = "io_input", issue = "none")] -pub use self::stdio::read_line; #[unstable(feature = "io_input_prompt", issue = "none")] pub use self::stdio::prompt_line; +#[unstable(feature = "io_input", issue = "none")] +pub use self::stdio::read_line; #[stable(feature = "rust1", since = "1.0.0")] pub use self::stdio::{stderr, stdin, stdout, Stderr, Stdin, Stdout}; #[stable(feature = "rust1", since = "1.0.0")] From d58892dd13792f73a59cf05de8ebe3ff6ce1b3c9 Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Sun, 13 Sep 2020 00:43:59 -0500 Subject: [PATCH 15/38] Update stdio.rs format --- library/std/src/io/stdio.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 47392e53ee587..8ec587578b0b3 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -5,9 +5,7 @@ use crate::io::prelude::*; use crate::cell::RefCell; use crate::fmt; use crate::io::lazy::Lazy; -use crate::io::{ - self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter, Write, -}; +use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter, Write}; use crate::result; use crate::str; use crate::sync::{Arc, Mutex, MutexGuard, Once}; @@ -921,7 +919,7 @@ impl fmt::Debug for StderrLock<'_> { /// #![feature(io_input)] /// use std::io; /// -/// fn main() -> io::Result<()> { +/// fn main() -> Result<()> { /// let name = io::read_line("Enter name: ")?; /// /// println!("Your name is {}!", name); @@ -959,7 +957,7 @@ where /// #![feature(io_input_prompt)] /// use std::io; /// -/// fn main() -> io::Result<()> { +/// fn main() -> Result<()> { /// let name = io::prompt_line("Enter name: ")?; /// /// println!("Your name is {}!", name); @@ -972,15 +970,16 @@ where reason = "this function may be replaced with a more general mechanism", issue = "none" )] -pub fn prompt_line(prompt: &str) -> result::Result::Err> +pub fn prompt_line( + prompt: &str +) -> result::Result::Err> where T: str::FromStr, ::Err: fmt::Debug, { let stdout = stdout(); let mut lock = stdout.lock(); - lock.write_all(prompt.as_bytes()) - .expect("failed to write whole buffer"); + lock.write_all(prompt.as_bytes()).expect("failed to write whole buffer"); lock.flush().expect("failed to flush stdout"); let mut input = String::new(); stdin().read_line(&mut input).expect("failed to read stdin"); From fd4cc45431557079c44174c58c00310fb6dd93b2 Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Sun, 13 Sep 2020 00:56:52 -0500 Subject: [PATCH 16/38] Update stdio.rs one comma! --- library/std/src/io/stdio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 8ec587578b0b3..4bd08af620a8f 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -971,7 +971,7 @@ where issue = "none" )] pub fn prompt_line( - prompt: &str + prompt: &str, ) -> result::Result::Err> where T: str::FromStr, From 8f2ca074c5c37ccf407da7793b447b70bf11c6fa Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Sun, 13 Sep 2020 01:22:03 -0500 Subject: [PATCH 17/38] Update stdio.rs dox --- library/std/src/io/stdio.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 4bd08af620a8f..960273a1e6684 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -919,7 +919,7 @@ impl fmt::Debug for StderrLock<'_> { /// #![feature(io_input)] /// use std::io; /// -/// fn main() -> Result<()> { +/// fn main() -> io::Result<()> { /// let name = io::read_line("Enter name: ")?; /// /// println!("Your name is {}!", name); @@ -957,7 +957,7 @@ where /// #![feature(io_input_prompt)] /// use std::io; /// -/// fn main() -> Result<()> { +/// fn main() -> io::Result<()> { /// let name = io::prompt_line("Enter name: ")?; /// /// println!("Your name is {}!", name); From ab4fb3e872ce14c147277fc28984fecb33bae726 Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Sun, 13 Sep 2020 09:07:55 -0500 Subject: [PATCH 18/38] Update stdio.rs docs --- library/std/src/io/stdio.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 960273a1e6684..2dcbd2f954174 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -919,12 +919,12 @@ impl fmt::Debug for StderrLock<'_> { /// #![feature(io_input)] /// use std::io; /// -/// fn main() -> io::Result<()> { -/// let name = io::read_line("Enter name: ")?; +/// fn main() { +/// println!("Enter name: "); /// -/// println!("Your name is {}!", name); +/// let name = io::read_line().unwrap(); /// -/// Ok(()) +/// println!("Your name is {}!", name); /// } /// ``` #[unstable( @@ -957,12 +957,10 @@ where /// #![feature(io_input_prompt)] /// use std::io; /// -/// fn main() -> io::Result<()> { -/// let name = io::prompt_line("Enter name: ")?; +/// fn main() { +/// let name = io::prompt_line("Enter name: ").unwrap(); /// /// println!("Your name is {}!", name); -/// -/// Ok(()) /// } /// ``` #[unstable( From 63feaa7ad0276895706bb33c23aafd7a80470163 Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Sun, 13 Sep 2020 09:37:45 -0500 Subject: [PATCH 19/38] Update stdio.rs docs!!! --- library/std/src/io/stdio.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 2dcbd2f954174..7d8ce30042e74 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -922,7 +922,7 @@ impl fmt::Debug for StderrLock<'_> { /// fn main() { /// println!("Enter name: "); /// -/// let name = io::read_line().unwrap(); +/// let name: String = io::read_line().unwrap(); /// /// println!("Your name is {}!", name); /// } @@ -958,7 +958,7 @@ where /// use std::io; /// /// fn main() { -/// let name = io::prompt_line("Enter name: ").unwrap(); +/// let name: String = io::prompt_line("Enter name: ").unwrap(); /// /// println!("Your name is {}!", name); /// } From 09d7391f5e3e006d2e48d03e69d1d924af78cd05 Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Sun, 20 Sep 2020 13:38:28 -0500 Subject: [PATCH 20/38] Update stdio.rs streamlined the function --- library/std/src/io/stdio.rs | 72 +++++++------------------------------ 1 file changed, 13 insertions(+), 59 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 7d8ce30042e74..6a050ed462a05 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -3,11 +3,9 @@ use crate::io::prelude::*; use crate::cell::RefCell; -use crate::fmt; use crate::io::lazy::Lazy; -use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter, Write}; +use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter, stdin, Result, Error, ErrorKind}; use crate::result; -use crate::str; use crate::sync::{Arc, Mutex, MutexGuard, Once}; use crate::sys::stdio; use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; @@ -905,46 +903,8 @@ impl fmt::Debug for StderrLock<'_> { } } -/// Similar to the [`prompt_line`] function, but does -/// not print a prompt. -/// -/// # Note -/// -/// If you require more explicit control over capturing -/// user input, see the [`Stdin::read_line`] method. -/// -/// # Examples -/// -/// ```no_run -/// #![feature(io_input)] -/// use std::io; -/// -/// fn main() { -/// println!("Enter name: "); -/// -/// let name: String = io::read_line().unwrap(); -/// -/// println!("Your name is {}!", name); -/// } -/// ``` -#[unstable( - feature = "io_input", - reason = "this function may be replaced with a more general mechanism", - issue = "none" -)] -pub fn read_line() -> result::Result::Err> -where - T: str::FromStr, - ::Err: fmt::Debug, -{ - let mut input = String::new(); - stdin().read_line(&mut input).expect("failed to read stdin"); - input.trim_end_matches(&['\n', '\r'][..]).parse::() -} - -/// Prints the given `str` and reads a [`String`] from -/// [standard input](Stdin). The trailing newline is stripped. -/// Gives an error on EOF (end of file). +/// Reads a [`String`] from [standard input](Stdin). The trailing +/// newline is stripped. Gives an error on EOF (end of file). /// /// # Note /// @@ -957,31 +917,25 @@ where /// #![feature(io_input_prompt)] /// use std::io; /// -/// fn main() { -/// let name: String = io::prompt_line("Enter name: ").unwrap(); +/// fn main() -> io::Result<()> { +/// let name: String = io::read_line("Enter name: ")?; /// /// println!("Your name is {}!", name); +/// +/// Ok(()) /// } /// ``` #[unstable( - feature = "io_input_prompt", + feature = "io_input", reason = "this function may be replaced with a more general mechanism", issue = "none" )] -pub fn prompt_line( - prompt: &str, -) -> result::Result::Err> -where - T: str::FromStr, - ::Err: fmt::Debug, -{ - let stdout = stdout(); - let mut lock = stdout.lock(); - lock.write_all(prompt.as_bytes()).expect("failed to write whole buffer"); - lock.flush().expect("failed to flush stdout"); +pub fn read_line() -> Result { let mut input = String::new(); - stdin().read_line(&mut input).expect("failed to read stdin"); - input.trim_end_matches(&['\n', '\r'][..]).parse::() + match stdin().read_line(&mut input)? { + 0 => Err(Error::new(ErrorKind::UnexpectedEof, "input reached eof unexpectedly")), + _ => Ok(String::from(input.trim_end_matches(&['\n', '\r'][..]))), + } } /// Resets the thread-local stderr handle to the specified writer From e65a3a9819e927d84d957a05832e74022110e140 Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Sun, 20 Sep 2020 13:39:02 -0500 Subject: [PATCH 21/38] Update mod.rs --- library/std/src/io/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index f803f6dcfb204..17e35a4d6b7e5 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -266,8 +266,6 @@ pub use self::buffered::{BufReader, BufWriter, LineWriter}; pub use self::cursor::Cursor; #[stable(feature = "rust1", since = "1.0.0")] pub use self::error::{Error, ErrorKind, Result}; -#[unstable(feature = "io_input_prompt", issue = "none")] -pub use self::stdio::prompt_line; #[unstable(feature = "io_input", issue = "none")] pub use self::stdio::read_line; #[stable(feature = "rust1", since = "1.0.0")] From f0571fab5c0b57277ea32060f6b2044d330bf80d Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Sun, 20 Sep 2020 13:39:28 -0500 Subject: [PATCH 22/38] Update stdio.rs --- library/std/src/io/stdio.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 6a050ed462a05..1d83ac094c989 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -5,7 +5,6 @@ use crate::io::prelude::*; use crate::cell::RefCell; use crate::io::lazy::Lazy; use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter, stdin, Result, Error, ErrorKind}; -use crate::result; use crate::sync::{Arc, Mutex, MutexGuard, Once}; use crate::sys::stdio; use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; From 2026394a0da248a04a8b0919716e78d8d76d67ea Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Sun, 20 Sep 2020 13:40:28 -0500 Subject: [PATCH 23/38] Update stdio.rs --- library/std/src/io/stdio.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 1d83ac094c989..0305696b257eb 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -3,6 +3,7 @@ use crate::io::prelude::*; use crate::cell::RefCell; +use crate::fmt; use crate::io::lazy::Lazy; use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter, stdin, Result, Error, ErrorKind}; use crate::sync::{Arc, Mutex, MutexGuard, Once}; From e79e87ba476e35ddccc83072500dd54ed9ee4753 Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Sun, 20 Sep 2020 13:44:38 -0500 Subject: [PATCH 24/38] Update stdio.rs --- library/std/src/io/stdio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 0305696b257eb..84e724427fe74 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -5,7 +5,7 @@ use crate::io::prelude::*; use crate::cell::RefCell; use crate::fmt; use crate::io::lazy::Lazy; -use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter, stdin, Result, Error, ErrorKind}; +use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter, Result, Error, ErrorKind}; use crate::sync::{Arc, Mutex, MutexGuard, Once}; use crate::sys::stdio; use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; From a45bf3a711224fc17f4f3de95867d86c9d33fbe8 Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Sun, 20 Sep 2020 13:59:09 -0500 Subject: [PATCH 25/38] Update stdio.rs --- library/std/src/io/stdio.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 84e724427fe74..3d6397baeefce 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -5,7 +5,9 @@ use crate::io::prelude::*; use crate::cell::RefCell; use crate::fmt; use crate::io::lazy::Lazy; -use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter, Result, Error, ErrorKind}; +use crate::io::{ + self, BufReader, Error, ErrorKind, Initializer, IoSlice, IoSliceMut, LineWriter, Result, +}; use crate::sync::{Arc, Mutex, MutexGuard, Once}; use crate::sys::stdio; use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; From a9070fa6f358a1dee4f44c8d601991ad7c75aac3 Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Sun, 20 Sep 2020 14:18:37 -0500 Subject: [PATCH 26/38] Update stdio.rs --- library/std/src/io/stdio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 3d6397baeefce..f58d3d08eca22 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -916,7 +916,7 @@ impl fmt::Debug for StderrLock<'_> { /// # Examples /// /// ```no_run -/// #![feature(io_input_prompt)] +/// #![feature(io_input)] /// use std::io; /// /// fn main() -> io::Result<()> { From 771001131029bfeabb8e9a2b00afe2d7e4e57517 Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Sun, 20 Sep 2020 14:46:19 -0500 Subject: [PATCH 27/38] Update stdio.rs --- library/std/src/io/stdio.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index f58d3d08eca22..31fc68fd1dd7a 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -920,7 +920,9 @@ impl fmt::Debug for StderrLock<'_> { /// use std::io; /// /// fn main() -> io::Result<()> { -/// let name: String = io::read_line("Enter name: ")?; +/// print!("Enter name: "); +/// +/// let name: String = io::read_line()?; /// /// println!("Your name is {}!", name); /// From 9d7f51fee4e699540ce3cfe20736542fdbd2818c Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Sun, 20 Sep 2020 22:44:20 -0500 Subject: [PATCH 28/38] Update stdio.rs --- library/std/src/io/stdio.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 31fc68fd1dd7a..0dc8b22ecd022 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -935,10 +935,19 @@ impl fmt::Debug for StderrLock<'_> { issue = "none" )] pub fn read_line() -> Result { + stdout().flush()?; // print!() does not flush :( let mut input = String::new(); match stdin().read_line(&mut input)? { 0 => Err(Error::new(ErrorKind::UnexpectedEof, "input reached eof unexpectedly")), - _ => Ok(String::from(input.trim_end_matches(&['\n', '\r'][..]))), + _ => { + if Some('\n') == input.chars().next_back() { + input.pop(); + if Some('\r') == input.chars().next_back() { + input.pop(); + } + } + Ok(input) + }, } } From 48f9aba32b365a04d115c842c5cb7bb0427185fc Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Sun, 20 Sep 2020 22:44:47 -0500 Subject: [PATCH 29/38] Update stdio.rs --- library/std/src/io/stdio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 0dc8b22ecd022..9f845cae20261 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -6,7 +6,7 @@ use crate::cell::RefCell; use crate::fmt; use crate::io::lazy::Lazy; use crate::io::{ - self, BufReader, Error, ErrorKind, Initializer, IoSlice, IoSliceMut, LineWriter, Result, + self, BufReader, Error, ErrorKind, Initializer, IoSlice, IoSliceMut, LineWriter, Result, Write, }; use crate::sync::{Arc, Mutex, MutexGuard, Once}; use crate::sys::stdio; From 4d4238e3c7fe3fcd06bc3ea70e0604794df099ee Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Sun, 20 Sep 2020 23:00:02 -0500 Subject: [PATCH 30/38] Update stdio.rs --- library/std/src/io/stdio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 9f845cae20261..51bbb0d8ea742 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -947,7 +947,7 @@ pub fn read_line() -> Result { } } Ok(input) - }, + } } } From 7ae7275928e92bb9c90f7983818f3baa1a7458bb Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Sat, 26 Sep 2020 20:23:05 -0500 Subject: [PATCH 31/38] Update stdio.rs better crossplatform newline remover --- library/std/src/io/stdio.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 51bbb0d8ea742..9de207a516870 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -940,12 +940,8 @@ pub fn read_line() -> Result { match stdin().read_line(&mut input)? { 0 => Err(Error::new(ErrorKind::UnexpectedEof, "input reached eof unexpectedly")), _ => { - if Some('\n') == input.chars().next_back() { - input.pop(); - if Some('\r') == input.chars().next_back() { - input.pop(); - } - } + input.pop(); + #[cfg(windows)] input.pop(); Ok(input) } } From 790b1d1a85d8305c5ffef54ca60a638af8726774 Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Sat, 26 Sep 2020 20:37:33 -0500 Subject: [PATCH 32/38] Update stdio.rs --- library/std/src/io/stdio.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 9de207a516870..baf58c74399f9 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -941,7 +941,8 @@ pub fn read_line() -> Result { 0 => Err(Error::new(ErrorKind::UnexpectedEof, "input reached eof unexpectedly")), _ => { input.pop(); - #[cfg(windows)] input.pop(); + #[cfg(windows)] + input.pop(); Ok(input) } } From c49a1ca3a1c7e835a01207525c33a301312dd2a0 Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Sun, 27 Sep 2020 13:04:58 -0500 Subject: [PATCH 33/38] Update stdio.rs merge conflicts --- library/std/src/io/stdio.rs | 379 ++++++++++++------------------------ 1 file changed, 122 insertions(+), 257 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index baf58c74399f9..fcb696e6bcec8 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -1,15 +1,19 @@ #![cfg_attr(test, allow(unused))] +#[cfg(test)] +mod tests; + use crate::io::prelude::*; use crate::cell::RefCell; use crate::fmt; -use crate::io::lazy::Lazy; use crate::io::{ self, BufReader, Error, ErrorKind, Initializer, IoSlice, IoSliceMut, LineWriter, Result, Write, }; -use crate::sync::{Arc, Mutex, MutexGuard, Once}; +use crate::lazy::SyncOnceCell; +use crate::sync::{Mutex, MutexGuard}; use crate::sys::stdio; +use crate::sys_common; use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; use crate::thread::LocalKey; @@ -52,8 +56,9 @@ struct StderrRaw(stdio::Stderr); /// handles is **not** available to raw handles returned from this function. /// /// The returned handle has no external synchronization or buffering. -fn stdin_raw() -> io::Result { - stdio::Stdin::new().map(StdinRaw) +#[unstable(feature = "libstd_sys_internals", issue = "none")] +const fn stdin_raw() -> StdinRaw { + StdinRaw(stdio::Stdin::new()) } /// Constructs a new raw handle to the standard output stream of this process. @@ -65,8 +70,9 @@ fn stdin_raw() -> io::Result { /// /// The returned handle has no external synchronization or buffering layered on /// top. -fn stdout_raw() -> io::Result { - stdio::Stdout::new().map(StdoutRaw) +#[unstable(feature = "libstd_sys_internals", issue = "none")] +const fn stdout_raw() -> StdoutRaw { + StdoutRaw(stdio::Stdout::new()) } /// Constructs a new raw handle to the standard error stream of this process. @@ -76,17 +82,18 @@ fn stdout_raw() -> io::Result { /// /// The returned handle has no external synchronization or buffering layered on /// top. -fn stderr_raw() -> io::Result { - stdio::Stderr::new().map(StderrRaw) +#[unstable(feature = "libstd_sys_internals", issue = "none")] +const 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) + handle_ebadf(self.0.read(buf), 0) } fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - self.0.read_vectored(bufs) + handle_ebadf(self.0.read_vectored(bufs), 0) } #[inline] @@ -100,25 +107,22 @@ impl Read for StdinRaw { } fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - self.0.read_to_end(buf) + handle_ebadf(self.0.read_to_end(buf), 0) } fn read_to_string(&mut self, buf: &mut String) -> io::Result { - self.0.read_to_string(buf) - } - - fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { - self.0.read_exact(buf) + handle_ebadf(self.0.read_to_string(buf), 0) } } impl Write for StdoutRaw { fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.write(buf) + handle_ebadf(self.0.write(buf), buf.len()) } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - self.0.write_vectored(bufs) + let total = bufs.iter().map(|b| b.len()).sum(); + handle_ebadf(self.0.write_vectored(bufs), total) } #[inline] @@ -127,29 +131,30 @@ impl Write for StdoutRaw { } fn flush(&mut self) -> io::Result<()> { - self.0.flush() + handle_ebadf(self.0.flush(), ()) } fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - self.0.write_all(buf) + handle_ebadf(self.0.write_all(buf), ()) } fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - self.0.write_all_vectored(bufs) + handle_ebadf(self.0.write_all_vectored(bufs), ()) } fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { - self.0.write_fmt(fmt) + handle_ebadf(self.0.write_fmt(fmt), ()) } } impl Write for StderrRaw { fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.write(buf) + handle_ebadf(self.0.write(buf), buf.len()) } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - self.0.write_vectored(bufs) + let total = bufs.iter().map(|b| b.len()).sum(); + handle_ebadf(self.0.write_vectored(bufs), total) } #[inline] @@ -158,80 +163,19 @@ impl Write for StderrRaw { } fn flush(&mut self) -> io::Result<()> { - self.0.flush() + handle_ebadf(self.0.flush(), ()) } fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - self.0.write_all(buf) + handle_ebadf(self.0.write_all(buf), ()) } fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - self.0.write_all_vectored(bufs) + handle_ebadf(self.0.write_all_vectored(bufs), ()) } fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { - self.0.write_fmt(fmt) - } -} - -enum Maybe { - Real(T), - Fake, -} - -impl io::Write for Maybe { - fn write(&mut self, buf: &[u8]) -> io::Result { - match *self { - Maybe::Real(ref mut w) => handle_ebadf(w.write(buf), buf.len()), - Maybe::Fake => Ok(buf.len()), - } - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - let total = bufs.iter().map(|b| b.len()).sum(); - match self { - Maybe::Real(w) => handle_ebadf(w.write_vectored(bufs), total), - Maybe::Fake => Ok(total), - } - } - - #[inline] - fn is_write_vectored(&self) -> bool { - match self { - Maybe::Real(w) => w.is_write_vectored(), - Maybe::Fake => true, - } - } - - fn flush(&mut self) -> io::Result<()> { - match *self { - Maybe::Real(ref mut w) => handle_ebadf(w.flush(), ()), - Maybe::Fake => Ok(()), - } - } -} - -impl io::Read for Maybe { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - match *self { - Maybe::Real(ref mut r) => handle_ebadf(r.read(buf), 0), - Maybe::Fake => Ok(0), - } - } - - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - match self { - Maybe::Real(r) => handle_ebadf(r.read_vectored(bufs), 0), - Maybe::Fake => Ok(0), - } - } - - #[inline] - fn is_read_vectored(&self) -> bool { - match self { - Maybe::Real(w) => w.is_read_vectored(), - Maybe::Fake => true, - } + handle_ebadf(self.0.write_fmt(fmt), ()) } } @@ -254,8 +198,7 @@ fn handle_ebadf(r: io::Result, default: T) -> io::Result { /// /// Created by the [`io::stdin`] method. /// -/// [`io::stdin`]: fn.stdin.html -/// [`BufRead`]: trait.BufRead.html +/// [`io::stdin`]: stdin /// /// ### Note: Windows Portability Consideration /// @@ -277,7 +220,7 @@ fn handle_ebadf(r: io::Result, default: T) -> io::Result { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Stdin { - inner: Arc>>>, + inner: &'static Mutex>, } /// A locked reference to the `Stdin` handle. @@ -285,10 +228,6 @@ pub struct Stdin { /// This handle implements both the [`Read`] and [`BufRead`] traits, and /// is constructed via the [`Stdin::lock`] method. /// -/// [`Read`]: trait.Read.html -/// [`BufRead`]: trait.BufRead.html -/// [`Stdin::lock`]: struct.Stdin.html#method.lock -/// /// ### Note: Windows Portability Consideration /// /// When operating in a console, the Windows implementation of this stream does not support @@ -312,7 +251,7 @@ pub struct Stdin { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct StdinLock<'a> { - inner: MutexGuard<'a, BufReader>>, + inner: MutexGuard<'a, BufReader>, } /// Constructs a new handle to the standard input of the current process. @@ -321,8 +260,6 @@ pub struct StdinLock<'a> { /// is synchronized via a mutex. If you need more explicit control over /// locking, see the [`Stdin::lock`] method. /// -/// [`Stdin::lock`]: struct.Stdin.html#method.lock -/// /// ### Note: Windows Portability Consideration /// When operating in a console, the Windows implementation of this stream does not support /// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return @@ -358,19 +295,11 @@ pub struct StdinLock<'a> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stdin() -> Stdin { - static INSTANCE: Lazy>>> = Lazy::new(); - return Stdin { - inner: unsafe { INSTANCE.get(stdin_init).expect("cannot access stdin during shutdown") }, - }; - - fn stdin_init() -> Arc>>> { - // This must not reentrantly access `INSTANCE` - let stdin = match stdin_raw() { - Ok(stdin) => Maybe::Real(stdin), - _ => Maybe::Fake, - }; - - Arc::new(Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin))) + static INSTANCE: SyncOnceCell>> = SyncOnceCell::new(); + Stdin { + inner: INSTANCE.get_or_init(|| { + Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin_raw())) + }), } } @@ -382,9 +311,6 @@ impl Stdin { /// returned guard also implements the [`Read`] and [`BufRead`] traits for /// accessing the underlying data. /// - /// [`Read`]: trait.Read.html - /// [`BufRead`]: trait.BufRead.html - /// /// # Examples /// /// ```no_run @@ -409,8 +335,6 @@ impl Stdin { /// For detailed semantics of this method, see the documentation on /// [`BufRead::read_line`]. /// - /// [`BufRead::read_line`]: trait.BufRead.html#method.read_line - /// /// # Examples /// /// ```no_run @@ -544,14 +468,14 @@ impl fmt::Debug for StdinLock<'_> { /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return /// an error. /// -/// [`lock`]: #method.lock -/// [`io::stdout`]: fn.stdout.html +/// [`lock`]: Stdout::lock +/// [`io::stdout`]: stdout #[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 // should also flush-on-panic or some form of flush-on-abort. - inner: Arc>>>>, + inner: &'static ReentrantMutex>>, } /// A locked reference to the `Stdout` handle. @@ -563,12 +487,9 @@ pub struct Stdout { /// When operating in a console, the Windows implementation of this stream does not support /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return /// an error. -/// -/// [`Write`]: trait.Write.html -/// [`Stdout::lock`]: struct.Stdout.html#method.lock #[stable(feature = "rust1", since = "1.0.0")] pub struct StdoutLock<'a> { - inner: ReentrantMutexGuard<'a, RefCell>>>, + inner: ReentrantMutexGuard<'a, RefCell>>, } /// Constructs a new handle to the standard output of the current process. @@ -577,8 +498,6 @@ pub struct StdoutLock<'a> { /// is synchronized via a mutex. If you need more explicit control over /// locking, see the [`Stdout::lock`] method. /// -/// [`Stdout::lock`]: struct.Stdout.html#method.lock -/// /// ### Note: Windows Portability Consideration /// When operating in a console, the Windows implementation of this stream does not support /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return @@ -614,22 +533,27 @@ pub struct StdoutLock<'a> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stdout() -> Stdout { - static INSTANCE: Lazy>>>> = Lazy::new(); - return Stdout { - inner: unsafe { INSTANCE.get(stdout_init).expect("cannot access stdout during shutdown") }, - }; - - fn stdout_init() -> Arc>>>> { - // This must not reentrantly access `INSTANCE` - let stdout = match stdout_raw() { - Ok(stdout) => Maybe::Real(stdout), - _ => Maybe::Fake, - }; - unsafe { - let ret = Arc::new(ReentrantMutex::new(RefCell::new(LineWriter::new(stdout)))); - ret.init(); - ret - } + static INSTANCE: SyncOnceCell>>> = + SyncOnceCell::new(); + Stdout { + inner: INSTANCE.get_or_init(|| unsafe { + let _ = sys_common::at_exit(|| { + if let Some(instance) = INSTANCE.get() { + // Flush the data and disable buffering during shutdown + // by replacing the line writer by one with zero + // buffering capacity. + // We use try_lock() instead of lock(), because someone + // might have leaked a StdoutLock, which would + // otherwise cause a deadlock here. + if let Some(lock) = instance.try_lock() { + *lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw()); + } + } + }); + let r = ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw()))); + r.init(); + r + }), } } @@ -722,11 +646,54 @@ impl fmt::Debug for StdoutLock<'_> { } } +/// Reads a [`String`] from [standard input](Stdin). The trailing +/// newline is stripped. Gives an error on EOF (end of file). +/// +/// # Note +/// +/// If you require more explicit control over capturing +/// user input, see the [`Stdin::read_line`] method. +/// +/// # Examples +/// +/// ```no_run +/// #![feature(io_input)] +/// use std::io; +/// +/// fn main() -> io::Result<()> { +/// print!("Enter name: "); +/// +/// let name: String = io::read_line()?; +/// +/// println!("Your name is {}!", name); +/// +/// Ok(()) +/// } +/// ``` +#[unstable( + feature = "io_input", + reason = "this function may be replaced with a more general mechanism", + issue = "none" +)] +pub fn read_line() -> Result { + stdout().flush()?; // print!() does not flush :( + let mut input = String::new(); + match stdin().read_line(&mut input)? { + 0 => Err(Error::new(ErrorKind::UnexpectedEof, "input reached eof unexpectedly")), + _ => { + input.pop(); + #[cfg(windows)] + input.pop(); + Ok(input) + } + } +} + /// A handle to the standard error stream of a process. /// /// For more information, see the [`io::stderr`] method. /// -/// [`io::stderr`]: fn.stderr.html +/// [`io::stderr`]: stderr /// /// ### Note: Windows Portability Consideration /// When operating in a console, the Windows implementation of this stream does not support @@ -734,7 +701,7 @@ impl fmt::Debug for StdoutLock<'_> { /// an error. #[stable(feature = "rust1", since = "1.0.0")] pub struct Stderr { - inner: &'static ReentrantMutex>>, + inner: &'static ReentrantMutex>, } /// A locked reference to the `Stderr` handle. @@ -742,15 +709,13 @@ pub struct Stderr { /// This handle implements the `Write` trait and is constructed via /// the [`Stderr::lock`] method. /// -/// [`Stderr::lock`]: struct.Stderr.html#method.lock -/// /// ### Note: Windows Portability Consideration /// When operating in a console, the Windows implementation of this stream does not support /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return /// an error. #[stable(feature = "rust1", since = "1.0.0")] pub struct StderrLock<'a> { - inner: ReentrantMutexGuard<'a, RefCell>>, + inner: ReentrantMutexGuard<'a, RefCell>, } /// Constructs a new handle to the standard error of the current process. @@ -799,21 +764,15 @@ pub fn stderr() -> Stderr { // // This has the added benefit of allowing `stderr` to be usable during // process shutdown as well! - static INSTANCE: ReentrantMutex>> = - unsafe { ReentrantMutex::new(RefCell::new(Maybe::Fake)) }; - - // When accessing stderr we need one-time initialization of the reentrant - // mutex, followed by one-time detection of whether we actually have a - // stderr handle or not. Afterwards we can just always use the now-filled-in - // `INSTANCE` value. - static INIT: Once = Once::new(); - INIT.call_once(|| unsafe { - INSTANCE.init(); - if let Ok(stderr) = stderr_raw() { - *INSTANCE.lock().borrow_mut() = Maybe::Real(stderr); - } - }); - Stderr { inner: &INSTANCE } + static INSTANCE: SyncOnceCell>> = SyncOnceCell::new(); + + Stderr { + inner: INSTANCE.get_or_init(|| unsafe { + let r = ReentrantMutex::new(RefCell::new(stderr_raw())); + r.init(); + r + }), + } } impl Stderr { @@ -821,7 +780,7 @@ impl Stderr { /// guard. /// /// The lock is released when the returned lock goes out of scope. The - /// returned guard also implements the `Write` trait for writing data. + /// returned guard also implements the [`Write`] trait for writing data. /// /// # Examples /// @@ -905,49 +864,6 @@ impl fmt::Debug for StderrLock<'_> { } } -/// Reads a [`String`] from [standard input](Stdin). The trailing -/// newline is stripped. Gives an error on EOF (end of file). -/// -/// # Note -/// -/// If you require more explicit control over capturing -/// user input, see the [`Stdin::read_line`] method. -/// -/// # Examples -/// -/// ```no_run -/// #![feature(io_input)] -/// use std::io; -/// -/// fn main() -> io::Result<()> { -/// print!("Enter name: "); -/// -/// let name: String = io::read_line()?; -/// -/// println!("Your name is {}!", name); -/// -/// Ok(()) -/// } -/// ``` -#[unstable( - feature = "io_input", - reason = "this function may be replaced with a more general mechanism", - issue = "none" -)] -pub fn read_line() -> Result { - stdout().flush()?; // print!() does not flush :( - let mut input = String::new(); - match stdin().read_line(&mut input)? { - 0 => Err(Error::new(ErrorKind::UnexpectedEof, "input reached eof unexpectedly")), - _ => { - input.pop(); - #[cfg(windows)] - input.pop(); - Ok(input) - } - } -} - /// Resets the thread-local stderr handle to the specified writer /// /// This will replace the current thread's stderr handle, returning the old @@ -1056,54 +972,3 @@ pub fn _eprint(args: fmt::Arguments<'_>) { #[cfg(test)] pub use realstd::io::{_eprint, _print}; - -#[cfg(test)] -mod tests { - use super::*; - use crate::panic::{RefUnwindSafe, UnwindSafe}; - use crate::thread; - - #[test] - fn stdout_unwind_safe() { - assert_unwind_safe::(); - } - #[test] - fn stdoutlock_unwind_safe() { - assert_unwind_safe::>(); - assert_unwind_safe::>(); - } - #[test] - fn stderr_unwind_safe() { - assert_unwind_safe::(); - } - #[test] - fn stderrlock_unwind_safe() { - assert_unwind_safe::>(); - assert_unwind_safe::>(); - } - - fn assert_unwind_safe() {} - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn panic_doesnt_poison() { - thread::spawn(|| { - let _a = stdin(); - let _a = _a.lock(); - let _a = stdout(); - let _a = _a.lock(); - let _a = stderr(); - let _a = _a.lock(); - panic!(); - }) - .join() - .unwrap_err(); - - let _a = stdin(); - let _a = _a.lock(); - let _a = stdout(); - let _a = _a.lock(); - let _a = stderr(); - let _a = _a.lock(); - } -} From 4608e07d1363d5af281e094edfc5801a0beb33f3 Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Sun, 27 Sep 2020 13:19:55 -0500 Subject: [PATCH 34/38] Update stdio.rs --- library/std/src/io/stdio.rs | 379 ++++++++++++++++++++++++------------ 1 file changed, 257 insertions(+), 122 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index fcb696e6bcec8..baf58c74399f9 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -1,19 +1,15 @@ #![cfg_attr(test, allow(unused))] -#[cfg(test)] -mod tests; - use crate::io::prelude::*; use crate::cell::RefCell; use crate::fmt; +use crate::io::lazy::Lazy; use crate::io::{ self, BufReader, Error, ErrorKind, Initializer, IoSlice, IoSliceMut, LineWriter, Result, Write, }; -use crate::lazy::SyncOnceCell; -use crate::sync::{Mutex, MutexGuard}; +use crate::sync::{Arc, Mutex, MutexGuard, Once}; use crate::sys::stdio; -use crate::sys_common; use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; use crate::thread::LocalKey; @@ -56,9 +52,8 @@ struct StderrRaw(stdio::Stderr); /// handles is **not** available to raw handles returned from this function. /// /// The returned handle has no external synchronization or buffering. -#[unstable(feature = "libstd_sys_internals", issue = "none")] -const fn stdin_raw() -> StdinRaw { - StdinRaw(stdio::Stdin::new()) +fn stdin_raw() -> io::Result { + stdio::Stdin::new().map(StdinRaw) } /// Constructs a new raw handle to the standard output stream of this process. @@ -70,9 +65,8 @@ const fn stdin_raw() -> StdinRaw { /// /// The returned handle has no external synchronization or buffering layered on /// top. -#[unstable(feature = "libstd_sys_internals", issue = "none")] -const fn stdout_raw() -> StdoutRaw { - StdoutRaw(stdio::Stdout::new()) +fn stdout_raw() -> io::Result { + stdio::Stdout::new().map(StdoutRaw) } /// Constructs a new raw handle to the standard error stream of this process. @@ -82,18 +76,17 @@ const fn stdout_raw() -> StdoutRaw { /// /// The returned handle has no external synchronization or buffering layered on /// top. -#[unstable(feature = "libstd_sys_internals", issue = "none")] -const fn stderr_raw() -> StderrRaw { - StderrRaw(stdio::Stderr::new()) +fn stderr_raw() -> io::Result { + stdio::Stderr::new().map(StderrRaw) } impl Read for StdinRaw { fn read(&mut self, buf: &mut [u8]) -> io::Result { - handle_ebadf(self.0.read(buf), 0) + self.0.read(buf) } fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { - handle_ebadf(self.0.read_vectored(bufs), 0) + self.0.read_vectored(bufs) } #[inline] @@ -107,22 +100,25 @@ impl Read for StdinRaw { } fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { - handle_ebadf(self.0.read_to_end(buf), 0) + self.0.read_to_end(buf) } fn read_to_string(&mut self, buf: &mut String) -> io::Result { - handle_ebadf(self.0.read_to_string(buf), 0) + self.0.read_to_string(buf) + } + + fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { + self.0.read_exact(buf) } } impl Write for StdoutRaw { fn write(&mut self, buf: &[u8]) -> io::Result { - handle_ebadf(self.0.write(buf), buf.len()) + self.0.write(buf) } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - let total = bufs.iter().map(|b| b.len()).sum(); - handle_ebadf(self.0.write_vectored(bufs), total) + self.0.write_vectored(bufs) } #[inline] @@ -131,30 +127,29 @@ impl Write for StdoutRaw { } fn flush(&mut self) -> io::Result<()> { - handle_ebadf(self.0.flush(), ()) + self.0.flush() } fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - handle_ebadf(self.0.write_all(buf), ()) + self.0.write_all(buf) } fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - handle_ebadf(self.0.write_all_vectored(bufs), ()) + self.0.write_all_vectored(bufs) } fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { - handle_ebadf(self.0.write_fmt(fmt), ()) + self.0.write_fmt(fmt) } } impl Write for StderrRaw { fn write(&mut self, buf: &[u8]) -> io::Result { - handle_ebadf(self.0.write(buf), buf.len()) + self.0.write(buf) } fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - let total = bufs.iter().map(|b| b.len()).sum(); - handle_ebadf(self.0.write_vectored(bufs), total) + self.0.write_vectored(bufs) } #[inline] @@ -163,19 +158,80 @@ impl Write for StderrRaw { } fn flush(&mut self) -> io::Result<()> { - handle_ebadf(self.0.flush(), ()) + self.0.flush() } fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - handle_ebadf(self.0.write_all(buf), ()) + self.0.write_all(buf) } fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - handle_ebadf(self.0.write_all_vectored(bufs), ()) + self.0.write_all_vectored(bufs) } fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { - handle_ebadf(self.0.write_fmt(fmt), ()) + self.0.write_fmt(fmt) + } +} + +enum Maybe { + Real(T), + Fake, +} + +impl io::Write for Maybe { + fn write(&mut self, buf: &[u8]) -> io::Result { + match *self { + Maybe::Real(ref mut w) => handle_ebadf(w.write(buf), buf.len()), + Maybe::Fake => Ok(buf.len()), + } + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + let total = bufs.iter().map(|b| b.len()).sum(); + match self { + Maybe::Real(w) => handle_ebadf(w.write_vectored(bufs), total), + Maybe::Fake => Ok(total), + } + } + + #[inline] + fn is_write_vectored(&self) -> bool { + match self { + Maybe::Real(w) => w.is_write_vectored(), + Maybe::Fake => true, + } + } + + fn flush(&mut self) -> io::Result<()> { + match *self { + Maybe::Real(ref mut w) => handle_ebadf(w.flush(), ()), + Maybe::Fake => Ok(()), + } + } +} + +impl io::Read for Maybe { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + match *self { + Maybe::Real(ref mut r) => handle_ebadf(r.read(buf), 0), + Maybe::Fake => Ok(0), + } + } + + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + match self { + Maybe::Real(r) => handle_ebadf(r.read_vectored(bufs), 0), + Maybe::Fake => Ok(0), + } + } + + #[inline] + fn is_read_vectored(&self) -> bool { + match self { + Maybe::Real(w) => w.is_read_vectored(), + Maybe::Fake => true, + } } } @@ -198,7 +254,8 @@ fn handle_ebadf(r: io::Result, default: T) -> io::Result { /// /// Created by the [`io::stdin`] method. /// -/// [`io::stdin`]: stdin +/// [`io::stdin`]: fn.stdin.html +/// [`BufRead`]: trait.BufRead.html /// /// ### Note: Windows Portability Consideration /// @@ -220,7 +277,7 @@ fn handle_ebadf(r: io::Result, default: T) -> io::Result { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Stdin { - inner: &'static Mutex>, + inner: Arc>>>, } /// A locked reference to the `Stdin` handle. @@ -228,6 +285,10 @@ pub struct Stdin { /// This handle implements both the [`Read`] and [`BufRead`] traits, and /// is constructed via the [`Stdin::lock`] method. /// +/// [`Read`]: trait.Read.html +/// [`BufRead`]: trait.BufRead.html +/// [`Stdin::lock`]: struct.Stdin.html#method.lock +/// /// ### Note: Windows Portability Consideration /// /// When operating in a console, the Windows implementation of this stream does not support @@ -251,7 +312,7 @@ pub struct Stdin { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct StdinLock<'a> { - inner: MutexGuard<'a, BufReader>, + inner: MutexGuard<'a, BufReader>>, } /// Constructs a new handle to the standard input of the current process. @@ -260,6 +321,8 @@ pub struct StdinLock<'a> { /// is synchronized via a mutex. If you need more explicit control over /// locking, see the [`Stdin::lock`] method. /// +/// [`Stdin::lock`]: struct.Stdin.html#method.lock +/// /// ### Note: Windows Portability Consideration /// When operating in a console, the Windows implementation of this stream does not support /// non-UTF-8 byte sequences. Attempting to read bytes that are not valid UTF-8 will return @@ -295,11 +358,19 @@ pub struct StdinLock<'a> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stdin() -> Stdin { - static INSTANCE: SyncOnceCell>> = SyncOnceCell::new(); - Stdin { - inner: INSTANCE.get_or_init(|| { - Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin_raw())) - }), + static INSTANCE: Lazy>>> = Lazy::new(); + return Stdin { + inner: unsafe { INSTANCE.get(stdin_init).expect("cannot access stdin during shutdown") }, + }; + + fn stdin_init() -> Arc>>> { + // This must not reentrantly access `INSTANCE` + let stdin = match stdin_raw() { + Ok(stdin) => Maybe::Real(stdin), + _ => Maybe::Fake, + }; + + Arc::new(Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin))) } } @@ -311,6 +382,9 @@ impl Stdin { /// returned guard also implements the [`Read`] and [`BufRead`] traits for /// accessing the underlying data. /// + /// [`Read`]: trait.Read.html + /// [`BufRead`]: trait.BufRead.html + /// /// # Examples /// /// ```no_run @@ -335,6 +409,8 @@ impl Stdin { /// For detailed semantics of this method, see the documentation on /// [`BufRead::read_line`]. /// + /// [`BufRead::read_line`]: trait.BufRead.html#method.read_line + /// /// # Examples /// /// ```no_run @@ -468,14 +544,14 @@ impl fmt::Debug for StdinLock<'_> { /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return /// an error. /// -/// [`lock`]: Stdout::lock -/// [`io::stdout`]: stdout +/// [`lock`]: #method.lock +/// [`io::stdout`]: fn.stdout.html #[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 // should also flush-on-panic or some form of flush-on-abort. - inner: &'static ReentrantMutex>>, + inner: Arc>>>>, } /// A locked reference to the `Stdout` handle. @@ -487,9 +563,12 @@ pub struct Stdout { /// When operating in a console, the Windows implementation of this stream does not support /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return /// an error. +/// +/// [`Write`]: trait.Write.html +/// [`Stdout::lock`]: struct.Stdout.html#method.lock #[stable(feature = "rust1", since = "1.0.0")] pub struct StdoutLock<'a> { - inner: ReentrantMutexGuard<'a, RefCell>>, + inner: ReentrantMutexGuard<'a, RefCell>>>, } /// Constructs a new handle to the standard output of the current process. @@ -498,6 +577,8 @@ pub struct StdoutLock<'a> { /// is synchronized via a mutex. If you need more explicit control over /// locking, see the [`Stdout::lock`] method. /// +/// [`Stdout::lock`]: struct.Stdout.html#method.lock +/// /// ### Note: Windows Portability Consideration /// When operating in a console, the Windows implementation of this stream does not support /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return @@ -533,27 +614,22 @@ pub struct StdoutLock<'a> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stdout() -> Stdout { - static INSTANCE: SyncOnceCell>>> = - SyncOnceCell::new(); - Stdout { - inner: INSTANCE.get_or_init(|| unsafe { - let _ = sys_common::at_exit(|| { - if let Some(instance) = INSTANCE.get() { - // Flush the data and disable buffering during shutdown - // by replacing the line writer by one with zero - // buffering capacity. - // We use try_lock() instead of lock(), because someone - // might have leaked a StdoutLock, which would - // otherwise cause a deadlock here. - if let Some(lock) = instance.try_lock() { - *lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw()); - } - } - }); - let r = ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw()))); - r.init(); - r - }), + static INSTANCE: Lazy>>>> = Lazy::new(); + return Stdout { + inner: unsafe { INSTANCE.get(stdout_init).expect("cannot access stdout during shutdown") }, + }; + + fn stdout_init() -> Arc>>>> { + // This must not reentrantly access `INSTANCE` + let stdout = match stdout_raw() { + Ok(stdout) => Maybe::Real(stdout), + _ => Maybe::Fake, + }; + unsafe { + let ret = Arc::new(ReentrantMutex::new(RefCell::new(LineWriter::new(stdout)))); + ret.init(); + ret + } } } @@ -646,54 +722,11 @@ impl fmt::Debug for StdoutLock<'_> { } } -/// Reads a [`String`] from [standard input](Stdin). The trailing -/// newline is stripped. Gives an error on EOF (end of file). -/// -/// # Note -/// -/// If you require more explicit control over capturing -/// user input, see the [`Stdin::read_line`] method. -/// -/// # Examples -/// -/// ```no_run -/// #![feature(io_input)] -/// use std::io; -/// -/// fn main() -> io::Result<()> { -/// print!("Enter name: "); -/// -/// let name: String = io::read_line()?; -/// -/// println!("Your name is {}!", name); -/// -/// Ok(()) -/// } -/// ``` -#[unstable( - feature = "io_input", - reason = "this function may be replaced with a more general mechanism", - issue = "none" -)] -pub fn read_line() -> Result { - stdout().flush()?; // print!() does not flush :( - let mut input = String::new(); - match stdin().read_line(&mut input)? { - 0 => Err(Error::new(ErrorKind::UnexpectedEof, "input reached eof unexpectedly")), - _ => { - input.pop(); - #[cfg(windows)] - input.pop(); - Ok(input) - } - } -} - /// A handle to the standard error stream of a process. /// /// For more information, see the [`io::stderr`] method. /// -/// [`io::stderr`]: stderr +/// [`io::stderr`]: fn.stderr.html /// /// ### Note: Windows Portability Consideration /// When operating in a console, the Windows implementation of this stream does not support @@ -701,7 +734,7 @@ pub fn read_line() -> Result { /// an error. #[stable(feature = "rust1", since = "1.0.0")] pub struct Stderr { - inner: &'static ReentrantMutex>, + inner: &'static ReentrantMutex>>, } /// A locked reference to the `Stderr` handle. @@ -709,13 +742,15 @@ pub struct Stderr { /// This handle implements the `Write` trait and is constructed via /// the [`Stderr::lock`] method. /// +/// [`Stderr::lock`]: struct.Stderr.html#method.lock +/// /// ### Note: Windows Portability Consideration /// When operating in a console, the Windows implementation of this stream does not support /// non-UTF-8 byte sequences. Attempting to write bytes that are not valid UTF-8 will return /// an error. #[stable(feature = "rust1", since = "1.0.0")] pub struct StderrLock<'a> { - inner: ReentrantMutexGuard<'a, RefCell>, + inner: ReentrantMutexGuard<'a, RefCell>>, } /// Constructs a new handle to the standard error of the current process. @@ -764,15 +799,21 @@ pub fn stderr() -> Stderr { // // This has the added benefit of allowing `stderr` to be usable during // process shutdown as well! - static INSTANCE: SyncOnceCell>> = SyncOnceCell::new(); - - Stderr { - inner: INSTANCE.get_or_init(|| unsafe { - let r = ReentrantMutex::new(RefCell::new(stderr_raw())); - r.init(); - r - }), - } + static INSTANCE: ReentrantMutex>> = + unsafe { ReentrantMutex::new(RefCell::new(Maybe::Fake)) }; + + // When accessing stderr we need one-time initialization of the reentrant + // mutex, followed by one-time detection of whether we actually have a + // stderr handle or not. Afterwards we can just always use the now-filled-in + // `INSTANCE` value. + static INIT: Once = Once::new(); + INIT.call_once(|| unsafe { + INSTANCE.init(); + if let Ok(stderr) = stderr_raw() { + *INSTANCE.lock().borrow_mut() = Maybe::Real(stderr); + } + }); + Stderr { inner: &INSTANCE } } impl Stderr { @@ -780,7 +821,7 @@ impl Stderr { /// guard. /// /// The lock is released when the returned lock goes out of scope. The - /// returned guard also implements the [`Write`] trait for writing data. + /// returned guard also implements the `Write` trait for writing data. /// /// # Examples /// @@ -864,6 +905,49 @@ impl fmt::Debug for StderrLock<'_> { } } +/// Reads a [`String`] from [standard input](Stdin). The trailing +/// newline is stripped. Gives an error on EOF (end of file). +/// +/// # Note +/// +/// If you require more explicit control over capturing +/// user input, see the [`Stdin::read_line`] method. +/// +/// # Examples +/// +/// ```no_run +/// #![feature(io_input)] +/// use std::io; +/// +/// fn main() -> io::Result<()> { +/// print!("Enter name: "); +/// +/// let name: String = io::read_line()?; +/// +/// println!("Your name is {}!", name); +/// +/// Ok(()) +/// } +/// ``` +#[unstable( + feature = "io_input", + reason = "this function may be replaced with a more general mechanism", + issue = "none" +)] +pub fn read_line() -> Result { + stdout().flush()?; // print!() does not flush :( + let mut input = String::new(); + match stdin().read_line(&mut input)? { + 0 => Err(Error::new(ErrorKind::UnexpectedEof, "input reached eof unexpectedly")), + _ => { + input.pop(); + #[cfg(windows)] + input.pop(); + Ok(input) + } + } +} + /// Resets the thread-local stderr handle to the specified writer /// /// This will replace the current thread's stderr handle, returning the old @@ -972,3 +1056,54 @@ pub fn _eprint(args: fmt::Arguments<'_>) { #[cfg(test)] pub use realstd::io::{_eprint, _print}; + +#[cfg(test)] +mod tests { + use super::*; + use crate::panic::{RefUnwindSafe, UnwindSafe}; + use crate::thread; + + #[test] + fn stdout_unwind_safe() { + assert_unwind_safe::(); + } + #[test] + fn stdoutlock_unwind_safe() { + assert_unwind_safe::>(); + assert_unwind_safe::>(); + } + #[test] + fn stderr_unwind_safe() { + assert_unwind_safe::(); + } + #[test] + fn stderrlock_unwind_safe() { + assert_unwind_safe::>(); + assert_unwind_safe::>(); + } + + fn assert_unwind_safe() {} + + #[test] + #[cfg_attr(target_os = "emscripten", ignore)] + fn panic_doesnt_poison() { + thread::spawn(|| { + let _a = stdin(); + let _a = _a.lock(); + let _a = stdout(); + let _a = _a.lock(); + let _a = stderr(); + let _a = _a.lock(); + panic!(); + }) + .join() + .unwrap_err(); + + let _a = stdin(); + let _a = _a.lock(); + let _a = stdout(); + let _a = _a.lock(); + let _a = stderr(); + let _a = _a.lock(); + } +} From c5715508edc0ffc714413e1ca6c1f468b9375e3a Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Mon, 28 Sep 2020 08:15:15 -0500 Subject: [PATCH 35/38] Update stdio.rs newline remover fix --- library/std/src/io/stdio.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index a52064b907f55..676e085fe45af 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -909,12 +909,7 @@ pub fn read_line() -> Result { let mut input = String::new(); match stdin().read_line(&mut input)? { 0 => Err(Error::new(ErrorKind::UnexpectedEof, "input reached eof unexpectedly")), - _ => { - input.pop(); - #[cfg(windows)] - input.pop(); - Ok(input) - } + _ => Ok(input.trim_end_matches(&['\n', '\r'][..]).to_owned()), } } From 9aa7bf82390182db3399014f467dedc926612d55 Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Mon, 28 Sep 2020 08:43:34 -0500 Subject: [PATCH 36/38] Update stdio.rs --- library/std/src/io/stdio.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 676e085fe45af..84e1bc768f9b1 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -909,7 +909,15 @@ pub fn read_line() -> Result { let mut input = String::new(); match stdin().read_line(&mut input)? { 0 => Err(Error::new(ErrorKind::UnexpectedEof, "input reached eof unexpectedly")), - _ => Ok(input.trim_end_matches(&['\n', '\r'][..]).to_owned()), + _ => { + if Some('\n') == input.chars().next_back() { + input.pop(); + if Some('\r') == input.chars().next_back() { + input.pop(); + } + } + Ok(input) + }, } } From d9d8b01c56e4321de7dd719d7376ee83792deb53 Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Mon, 28 Sep 2020 08:51:57 -0500 Subject: [PATCH 37/38] Update stdio.rs --- library/std/src/io/stdio.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 84e1bc768f9b1..a3715c7c7bb77 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -910,9 +910,9 @@ pub fn read_line() -> Result { match stdin().read_line(&mut input)? { 0 => Err(Error::new(ErrorKind::UnexpectedEof, "input reached eof unexpectedly")), _ => { - if Some('\n') == input.chars().next_back() { + if input.ends_with('\n') { input.pop(); - if Some('\r') == input.chars().next_back() { + if cfg!(windows) && input.ends_with('\r') { input.pop(); } } From 45b8a1ddad9e35a868f7b9eebcb67c9b0a16aa89 Mon Sep 17 00:00:00 2001 From: sHaDoW Date: Mon, 28 Sep 2020 09:04:23 -0500 Subject: [PATCH 38/38] Update stdio.rs --- library/std/src/io/stdio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index a3715c7c7bb77..a2d59fbb5a163 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -917,7 +917,7 @@ pub fn read_line() -> Result { } } Ok(input) - }, + } } }