From 04479b13c3a80895fc642079dfd465a640be58a9 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Sun, 13 Oct 2019 12:13:29 +0200 Subject: [PATCH 1/4] add io::stdio Signed-off-by: Yoshua Wuyts --- src/io/mod.rs | 1 + src/io/stdio.rs | 29 +++++++++++++++++++++++++++++ src/lib.rs | 1 + src/macros.rs | 43 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+) create mode 100644 src/io/stdio.rs create mode 100644 src/macros.rs diff --git a/src/io/mod.rs b/src/io/mod.rs index 7a942854..eef6d731 100644 --- a/src/io/mod.rs +++ b/src/io/mod.rs @@ -55,5 +55,6 @@ mod repeat; mod sink; mod stderr; mod stdin; +mod stdio; mod stdout; mod timeout; diff --git a/src/io/stdio.rs b/src/io/stdio.rs new file mode 100644 index 00000000..2a4a3665 --- /dev/null +++ b/src/io/stdio.rs @@ -0,0 +1,29 @@ +//! Internal types for stdio. +//! +//! This module is a port of `libstd/io/stdio.rs`,and contains internal types for `print`/`eprint`. + +use crate::io::{stderr, stdout, Write}; +use std::fmt; + +/// Write `args` `global_s`. `label` identifies the stream in a panic message. +async fn print_to( + args: fmt::Arguments<'_>, + global_s: fn() -> T, + label: &str, +) where + T: Write, +{ + if let Err(e) = global_s().write_fmt(args).await { + panic!("failed printing to {}: {}", label, e); + } +} + +#[doc(hidden)] +pub async fn _print(args: fmt::Arguments<'_>) { + print_to(args, stdout, "stdout"); +} + +#[doc(hidden)] +pub async fn _eprint(args: fmt::Arguments<'_>) { + print_to(args, stderr, "stderr"); +} diff --git a/src/lib.rs b/src/lib.rs index f1ed43e1..f69d1f89 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -76,6 +76,7 @@ cfg_if! { } } +mod macros; pub(crate) mod utils; #[doc(inline)] diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 00000000..80d784da --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,43 @@ +/// Prints to the standard output. +/// +/// Equivalent to the [`println!`] macro except that a newline is not printed at +/// the end of the message. +/// +/// Note that stdout is frequently line-buffered by default so it may be +/// necessary to use [`io::stdout().flush()`][flush] to ensure the output is emitted +/// immediately. +/// +/// Use `print!` only for the primary output of your program. Use +/// [`eprint!`] instead to print error and progress messages. +/// +/// [`println!`]: macro.println.html +/// [flush]: io/trait.Write.html#tymethod.flush +/// [`eprint!`]: macro.eprint.html +/// +/// # Panics +/// +/// Panics if writing to `io::stdout()` fails. +/// +/// # Examples +/// +/// ``` +/// use std::io::{self, Write}; +/// +/// print!("this "); +/// print!("will "); +/// print!("be "); +/// print!("on "); +/// print!("the "); +/// print!("same "); +/// print!("line "); +/// +/// io::stdout().flush().unwrap(); +/// +/// print!("this string has a newline, why not choose println! instead?\n"); +/// +/// io::stdout().flush().unwrap(); +/// ``` +#[macro_export] +macro_rules! print { + ($($arg:tt)*) => ($crate::io::_print(format_args!($($arg)*))); +} From 296d0d9d317a569f7cdf621809ceee356f5de578 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Sun, 13 Oct 2019 12:48:41 +0200 Subject: [PATCH 2/4] add print macros Signed-off-by: Yoshua Wuyts --- src/io/mod.rs | 4 ++ src/io/stdio.rs | 26 +++----- src/io/write/write_fmt.rs | 2 +- src/macros.rs | 136 ++++++++++++++++++++++++++++++++++---- 4 files changed, 138 insertions(+), 30 deletions(-) diff --git a/src/io/mod.rs b/src/io/mod.rs index eef6d731..812c97ab 100644 --- a/src/io/mod.rs +++ b/src/io/mod.rs @@ -39,6 +39,10 @@ pub use stdout::{stdout, Stdout}; pub use timeout::timeout; pub use write::Write; +// For use in the print macros. +#[doc(hidden)] +pub use stdio::{_eprint, _print}; + pub mod prelude; pub(crate) mod buf_read; diff --git a/src/io/stdio.rs b/src/io/stdio.rs index 2a4a3665..33d9e404 100644 --- a/src/io/stdio.rs +++ b/src/io/stdio.rs @@ -2,28 +2,20 @@ //! //! This module is a port of `libstd/io/stdio.rs`,and contains internal types for `print`/`eprint`. -use crate::io::{stderr, stdout, Write}; +use crate::prelude::*; +use crate::io::{stderr, stdout}; use std::fmt; -/// Write `args` `global_s`. `label` identifies the stream in a panic message. -async fn print_to( - args: fmt::Arguments<'_>, - global_s: fn() -> T, - label: &str, -) where - T: Write, -{ - if let Err(e) = global_s().write_fmt(args).await { - panic!("failed printing to {}: {}", label, e); +#[doc(hidden)] +pub async fn _print(args: fmt::Arguments<'_>) { + if let Err(e) = stdout().write_fmt(args).await { + panic!("failed printing to stdout: {}", e); } } -#[doc(hidden)] -pub async fn _print(args: fmt::Arguments<'_>) { - print_to(args, stdout, "stdout"); -} - #[doc(hidden)] pub async fn _eprint(args: fmt::Arguments<'_>) { - print_to(args, stderr, "stderr"); + if let Err(e) = stderr().write_fmt(args).await { + panic!("failed printing to stderr: {}", e); + } } diff --git a/src/io/write/write_fmt.rs b/src/io/write/write_fmt.rs index f5942289..a1149cde 100644 --- a/src/io/write/write_fmt.rs +++ b/src/io/write/write_fmt.rs @@ -36,7 +36,7 @@ impl Future for WriteFmtFuture<'_, T> { // Copy the data from the buffer into the writer until it's done. loop { - if buffer.is_empty() { + if *amt == buffer.len() as u64 { futures_core::ready!(Pin::new(&mut **writer).poll_flush(cx))?; return Poll::Ready(Ok(())); } diff --git a/src/macros.rs b/src/macros.rs index 80d784da..d06238c3 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -21,23 +21,135 @@ /// # Examples /// /// ``` -/// use std::io::{self, Write}; +/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { +/// # +/// use async_std::prelude::*; +/// use async_std::io; +/// use async_std::print; /// -/// print!("this "); -/// print!("will "); -/// print!("be "); -/// print!("on "); -/// print!("the "); -/// print!("same "); -/// print!("line "); +/// print!("this ").await; +/// print!("will ").await; +/// print!("be ").await; +/// print!("on ").await; +/// print!("the ").await; +/// print!("same ").await; +/// print!("line ").await; /// -/// io::stdout().flush().unwrap(); +/// io::stdout().flush().await.unwrap(); /// -/// print!("this string has a newline, why not choose println! instead?\n"); +/// print!("this string has a newline, why not choose println! instead?\n").await; /// -/// io::stdout().flush().unwrap(); +/// io::stdout().flush().await.unwrap(); +/// # +/// # Ok(()) }) } /// ``` #[macro_export] macro_rules! print { - ($($arg:tt)*) => ($crate::io::_print(format_args!($($arg)*))); + ($($arg:tt)*) => ($crate::io::_print(format_args!($($arg)*))) +} + +/// Prints to the standard output, with a newline. +/// +/// On all platforms, the newline is the LINE FEED character (`\n`/`U+000A`) alone +/// (no additional CARRIAGE RETURN (`\r`/`U+000D`)). +/// +/// Use the [`format!`] syntax to write data to the standard output. +/// See [`std::fmt`] for more information. +/// +/// Use `println!` only for the primary output of your program. Use +/// [`eprintln!`] instead to print error and progress messages. +/// +/// [`format!`]: macro.format.html +/// [`std::fmt`]: https://doc.rust-lang.org/std/fmt/index.html +/// [`eprintln!`]: macro.eprintln.html +/// # Panics +/// +/// Panics if writing to `io::stdout` fails. +/// +/// # Examples +/// +/// ``` +/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { +/// # +/// use async_std::println; +/// +/// println!().await; // prints just a newline +/// println!("hello there!").await; +/// println!("format {} arguments", "some").await; +/// # +/// # Ok(()) }) } +/// ``` +#[macro_export] +macro_rules! println { + () => ($crate::print!("\n")); + ($($arg:tt)*) => ($crate::io::_print(format_args!($($arg)*))) +} + +/// Prints to the standard error. +/// +/// Equivalent to the [`print!`] macro, except that output goes to +/// [`io::stderr`] instead of `io::stdout`. See [`print!`] for +/// example usage. +/// +/// Use `eprint!` only for error and progress messages. Use `print!` +/// instead for the primary output of your program. +/// +/// [`io::stderr`]: io/struct.Stderr.html +/// [`print!`]: macro.print.html +/// +/// # Panics +/// +/// Panics if writing to `io::stderr` fails. +/// +/// # Examples +/// +/// ``` +/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { +/// # +/// use async_std::eprint; +/// +/// eprint!("Error: Could not complete task").await; +/// # +/// # Ok(()) }) } +/// ``` +#[macro_export] +macro_rules! eprint { + ($($arg:tt)*) => ($crate::io::_eprint(format_args!($($arg)*))) +} + +/// Prints to the standard error, with a newline. +/// +/// Equivalent to the [`println!`] macro, except that output goes to +/// [`io::stderr`] instead of `io::stdout`. See [`println!`] for +/// example usage. +/// +/// Use `eprintln!` only for error and progress messages. Use `println!` +/// instead for the primary output of your program. +/// +/// [`io::stderr`]: io/struct.Stderr.html +/// [`println!`]: macro.println.html +/// +/// # Panics +/// +/// Panics if writing to `io::stderr` fails. +/// +/// # Examples +/// +/// ``` +/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { +/// # +/// use async_std::eprintln; +/// +/// eprintln!("Error: Could not complete task").await; +/// # +/// # Ok(()) }) } +/// ``` +#[macro_export] +macro_rules! eprintln { + () => (async { $crate::eprint!("\n").await; }); + ($($arg:tt)*) => ( + async { + $crate::io::_eprint(format_args!($($arg)*)).await; + } + ); } From 467b64b6e75cac797dde8f63ea8133b99f9a7c76 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Sun, 13 Oct 2019 12:51:21 +0200 Subject: [PATCH 3/4] doc fmt Signed-off-by: Yoshua Wuyts --- src/macros.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index d06238c3..d7e4ae44 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -21,7 +21,7 @@ /// # Examples /// /// ``` -/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { +/// # async_std::task::block_on(async { /// # /// use async_std::prelude::*; /// use async_std::io; @@ -41,7 +41,7 @@ /// /// io::stdout().flush().await.unwrap(); /// # -/// # Ok(()) }) } +/// # }) /// ``` #[macro_export] macro_rules! print { @@ -69,7 +69,7 @@ macro_rules! print { /// # Examples /// /// ``` -/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { +/// # async_std::task::block_on(async { /// # /// use async_std::println; /// @@ -77,7 +77,7 @@ macro_rules! print { /// println!("hello there!").await; /// println!("format {} arguments", "some").await; /// # -/// # Ok(()) }) } +/// # }) /// ``` #[macro_export] macro_rules! println { @@ -104,13 +104,13 @@ macro_rules! println { /// # Examples /// /// ``` -/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { +/// # async_std::task::block_on(async { /// # /// use async_std::eprint; /// /// eprint!("Error: Could not complete task").await; /// # -/// # Ok(()) }) } +/// # }) /// ``` #[macro_export] macro_rules! eprint { @@ -136,13 +136,13 @@ macro_rules! eprint { /// # Examples /// /// ``` -/// # fn main() -> std::io::Result<()> { async_std::task::block_on(async { +/// # async_std::task::block_on(async { /// # /// use async_std::eprintln; /// /// eprintln!("Error: Could not complete task").await; /// # -/// # Ok(()) }) } +/// # }) /// ``` #[macro_export] macro_rules! eprintln { From fef2e32a3c39e129fafce92c21396bf351d6a165 Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Sun, 13 Oct 2019 13:07:52 +0200 Subject: [PATCH 4/4] cargo fmt Signed-off-by: Yoshua Wuyts --- src/io/stdio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/io/stdio.rs b/src/io/stdio.rs index 33d9e404..0e11e1a9 100644 --- a/src/io/stdio.rs +++ b/src/io/stdio.rs @@ -2,8 +2,8 @@ //! //! This module is a port of `libstd/io/stdio.rs`,and contains internal types for `print`/`eprint`. -use crate::prelude::*; use crate::io::{stderr, stdout}; +use crate::prelude::*; use std::fmt; #[doc(hidden)]