diff --git a/src/io/mod.rs b/src/io/mod.rs index eef6d73..812c97a 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 2a4a366..33d9e40 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<'_>) { - print_to(args, stdout, "stdout"); + if let Err(e) = stdout().write_fmt(args).await { + panic!("failed printing to stdout: {}", e); + } } #[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 f594228..a1149cd 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 80d784d..d06238c 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; + } + ); }