diff --git a/src/lib.rs b/src/lib.rs index fb2e6bf..2e36f4d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,16 +23,21 @@ mod join; mod join_stream; mod maybe_done; mod poll_fn; +mod print; mod ready; mod select; +mod task_local; mod try_join; mod try_select; pub use join_stream::JoinStream; pub use maybe_done::MaybeDone; +pub use std::{write, writeln}; /// Helper re-exports for use in macros. pub mod utils { pub use super::poll_fn::poll_fn; pub use core::{future, pin, result, task}; + pub use std::format_args; + pub use std::panic; } diff --git a/src/print.rs b/src/print.rs new file mode 100644 index 0000000..71300bb --- /dev/null +++ b/src/print.rs @@ -0,0 +1,185 @@ +/// 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 +/// +/// ```ignore +/// # async_std::task::block_on(async { +/// # +/// use async_std::prelude::*; +/// use async_std::io; +/// use async_std::print; +/// +/// print!("this ").await; +/// print!("will ").await; +/// print!("be ").await; +/// print!("on ").await; +/// print!("the ").await; +/// print!("same ").await; +/// print!("line ").await; +/// +/// io::stdout().flush().await.unwrap(); +/// +/// print!("this string has a newline, why not choose println! instead?\n").await; +/// +/// io::stdout().flush().await.unwrap(); +/// # +/// # }) +/// ``` +#[macro_export] +macro_rules! print { + ($($arg:tt)*) => ({ + let args = $crate::utils::format_args!($($arg)*); + async move { + use ::async_std::prelude::*; + if let Err(e) = ::async_std::io::stdout().write_fmt(args).await { + $crate::utils::panic!("failed printing to stdout: {}", e); + } + } + }); +} + +/// 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 +/// +/// ```ignore +/// # 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; +/// # +/// # }) +/// ``` +#[macro_export] +macro_rules! println { + () => ($crate::print!("\n")); + ($($arg:tt)*) => ({ + let args = $crate::utils::format_args!($($arg)*); + async move { + use ::async_std::prelude::*; + if let Err(e) = ::async_std::io::stdout().write_fmt(args).await { + $crate::utils::panic!("failed printing to stdout: {}", e); + } + $crate::print!("\n").await; + } + }); +} + +/// 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 +/// +/// ```ignore +/// # async_std::task::block_on(async { +/// # +/// use async_std::eprint; +/// +/// eprint!("Error: Could not complete task").await; +/// # +/// # }) +/// ``` +#[macro_export] +macro_rules! eprint { + ($($arg:tt)*) => ({ + let args = $crate::utils::format_args!($($arg)*); + async move { + use ::async_std::prelude::*; + if let Err(e) = ::async_std::io::stderr().write_fmt(args).await { + $crate::utils::panic!("failed printing to stderr: {}", e); + } + } + }); +} + +/// 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 +/// +/// ```ignore +/// # async_std::task::block_on(async { +/// # +/// use async_std::eprintln; +/// +/// eprintln!("Error: Could not complete task").await; +/// # +/// # }) +/// ``` +#[macro_export] +macro_rules! eprintln { + () => ($crate::eprint!("\n")); + ($($arg:tt)*) => ({ + let args = $crate::utils::format_args!($($arg)*); + async move { + use ::async_std::prelude::*; + if let Err(e) = ::async_std::io::stderr().write_fmt(args).await { + $crate::utils::panic!("failed printing to stderr: {}", e); + } + $crate::eprint!("\n").await; + } + }); +} diff --git a/src/task_local.rs b/src/task_local.rs new file mode 100644 index 0000000..1664f89 --- /dev/null +++ b/src/task_local.rs @@ -0,0 +1,50 @@ +/// Declares task-local values. +/// +/// The macro wraps any number of static declarations and makes them task-local. Attributes and +/// visibility modifiers are allowed. +/// +/// Each declared value is of the accessor type [`LocalKey`]. +/// +/// [`LocalKey`]: task/struct.LocalKey.html +/// +/// # Examples +/// +/// ```ignore +/// # +/// use std::cell::Cell; +/// +/// use async_std::task; +/// use async_std::prelude::*; +/// +/// task_local! { +/// static VAL: Cell = Cell::new(5); +/// } +/// +/// task::block_on(async { +/// let v = VAL.with(|c| c.get()); +/// assert_eq!(v, 5); +/// }); +/// ``` +#[macro_export] +macro_rules! task_local { + () => (); + + ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr) => ( + $(#[$attr])* $vis static $name: ::async_std::task::LocalKey<$t> = { + #[inline] + fn __init() -> $t { + $init + } + + ::async_std::task::LocalKey { + __init, + __key: ::std::sync::atomic::AtomicUsize::new(0), + } + }; + ); + + ($(#[$attr:meta])* $vis:vis static $name:ident: $t:ty = $init:expr; $($rest:tt)*) => ( + $crate::task_local!($(#[$attr])* $vis static $name: $t = $init); + $crate::task_local!($($rest)*); + ); +}