aboutsummaryrefslogtreecommitdiff
path: root/ctr-std/src/macros.rs
diff options
context:
space:
mode:
Diffstat (limited to 'ctr-std/src/macros.rs')
-rw-r--r--ctr-std/src/macros.rs367
1 files changed, 313 insertions, 54 deletions
diff --git a/ctr-std/src/macros.rs b/ctr-std/src/macros.rs
index 21a7da9..f058b1c 100644
--- a/ctr-std/src/macros.rs
+++ b/ctr-std/src/macros.rs
@@ -16,13 +16,38 @@
/// The entry point for panic of Rust threads.
///
+/// This allows a program to to terminate immediately and provide feedback
+/// to the caller of the program. `panic!` should be used when a program reaches
+/// an unrecoverable problem.
+///
+/// This macro is the perfect way to assert conditions in example code and in
+/// tests. `panic!` is closely tied with the `unwrap` method of both [`Option`]
+/// and [`Result`][runwrap] enums. Both implementations call `panic!` when they are set
+/// to None or Err variants.
+///
/// This macro is used to inject panic into a Rust thread, causing the thread to
/// panic entirely. Each thread's panic can be reaped as the `Box<Any>` type,
/// and the single-argument form of the `panic!` macro will be the value which
/// is transmitted.
///
+/// [`Result`] enum is often a better solution for recovering from errors than
+/// using the `panic!` macro. This macro should be used to avoid proceeding using
+/// incorrect values, such as from external sources. Detailed information about
+/// error handling is found in the [book].
+///
/// The multi-argument form of this macro panics with a string and has the
-/// `format!` syntax for building a string.
+/// [`format!`] syntax for building a string.
+///
+/// [runwrap]: ../std/result/enum.Result.html#method.unwrap
+/// [`Option`]: ../std/option/enum.Option.html#method.unwrap
+/// [`Result`]: ../std/result/enum.Result.html
+/// [`format!`]: ../std/macro.format.html
+/// [book]: ../book/second-edition/ch09-01-unrecoverable-errors-with-panic.html
+///
+/// # Current implementation
+///
+/// If the main thread panics it will terminate all your threads and end your
+/// program with code `101`.
///
/// # Examples
///
@@ -41,33 +66,30 @@ macro_rules! panic {
panic!("explicit panic")
});
($msg:expr) => ({
- $crate::rt::begin_panic($msg, {
- // static requires less code at runtime, more constant data
- static _FILE_LINE_COL: (&'static str, u32, u32) = (file!(), line!(), column!());
- &_FILE_LINE_COL
- })
+ $crate::rt::begin_panic($msg, &(file!(), line!(), __rust_unstable_column!()))
});
($fmt:expr, $($arg:tt)+) => ({
- $crate::rt::begin_panic_fmt(&format_args!($fmt, $($arg)+), {
- // The leading _'s are to avoid dead code warnings if this is
- // used inside a dead function. Just `#[allow(dead_code)]` is
- // insufficient, since the user may have
- // `#[forbid(dead_code)]` and which cannot be overridden.
- static _FILE_LINE_COL: (&'static str, u32, u32) = (file!(), line!(), column!());
- &_FILE_LINE_COL
- })
+ $crate::rt::begin_panic_fmt(&format_args!($fmt, $($arg)+),
+ &(file!(), line!(), __rust_unstable_column!()))
});
}
/// Macro for printing to the standard output.
///
-/// Equivalent to the `println!` macro except that a newline is not printed at
+/// 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()` to ensure the output is emitted
+/// 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!`]: ../std/macro.println.html
+/// [flush]: ../std/io/trait.Write.html#tymethod.flush
+/// [`eprint!`]: ../std/macro.eprint.html
+///
/// # Panics
///
/// Panics if writing to `io::stdout()` fails.
@@ -98,21 +120,28 @@ macro_rules! print {
($($arg:tt)*) => ($crate::io::_print(format_args!($($arg)*)));
}
-/// Macro for printing to the standard output, with a newline. On all
-/// platforms, the newline is the LINE FEED character (`\n`/`U+000A`) alone
+/// Macro for printing 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 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!`]: ../std/macro.format.html
+/// [`std::fmt`]: ../std/fmt/index.html
+/// [`eprintln!`]: ../std/macro.eprint.html
/// # Panics
///
-/// Panics if writing to `io::stdout()` fails.
+/// Panics if writing to `io::stdout` fails.
///
/// # Examples
///
/// ```
-/// println!();
+/// println!(); // prints just a newline
/// println!("hello there!");
/// println!("format {} arguments", "some");
/// ```
@@ -124,6 +153,63 @@ macro_rules! println {
($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
}
+/// Macro for printing 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`]: ../std/io/struct.Stderr.html
+/// [`print!`]: ../std/macro.print.html
+///
+/// # Panics
+///
+/// Panics if writing to `io::stderr` fails.
+///
+/// # Examples
+///
+/// ```
+/// eprint!("Error: Could not complete task");
+/// ```
+#[macro_export]
+#[stable(feature = "eprint", since = "1.19.0")]
+#[allow_internal_unstable]
+macro_rules! eprint {
+ ($($arg:tt)*) => ($crate::io::_eprint(format_args!($($arg)*)));
+}
+
+/// Macro for printing 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`]: ../std/io/struct.Stderr.html
+/// [`println!`]: ../std/macro.println.html
+///
+/// # Panics
+///
+/// Panics if writing to `io::stderr` fails.
+///
+/// # Examples
+///
+/// ```
+/// eprintln!("Error: Could not complete task");
+/// ```
+#[macro_export]
+#[stable(feature = "eprint", since = "1.19.0")]
+macro_rules! eprintln {
+ () => (eprint!("\n"));
+ ($fmt:expr) => (eprint!(concat!($fmt, "\n")));
+ ($fmt:expr, $($arg:tt)*) => (eprint!(concat!($fmt, "\n"), $($arg)*));
+}
+
/// A macro to select an event from a number of receivers.
///
/// This macro is used to wait for the first event to occur on a number of
@@ -193,15 +279,60 @@ macro_rules! assert_approx_eq {
/// into libsyntax itself.
#[cfg(dox)]
pub mod builtin {
+
+ /// Unconditionally causes compilation to fail with the given error message when encountered.
+ ///
+ /// This macro should be used when a crate uses a conditional compilation strategy to provide
+ /// better error messages for erroneous conditions.
+ ///
+ /// # Examples
+ ///
+ /// Two such examples are macros and `#[cfg]` environments.
+ ///
+ /// Emit better compiler error if a macro is passed invalid values.
+ ///
+ /// ```compile_fail
+ /// macro_rules! give_me_foo_or_bar {
+ /// (foo) => {};
+ /// (bar) => {};
+ /// ($x:ident) => {
+ /// compile_error!("This macro only accepts `foo` or `bar`");
+ /// }
+ /// }
+ ///
+ /// give_me_foo_or_bar!(neither);
+ /// // ^ will fail at compile time with message "This macro only accepts `foo` or `bar`"
+ /// ```
+ ///
+ /// Emit compiler error if one of a number of features isn't available.
+ ///
+ /// ```compile_fail
+ /// #[cfg(not(any(feature = "foo", feature = "bar")))]
+ /// compile_error!("Either feature \"foo\" or \"bar\" must be enabled for this crate.")
+ /// ```
+ #[stable(feature = "compile_error_macro", since = "1.20.0")]
+ #[macro_export]
+ macro_rules! compile_error { ($msg:expr) => ({ /* compiler built-in */ }) }
+
/// The core macro for formatted string creation & output.
///
+ /// This macro functions by taking a formatting string literal containing
+ /// `{}` for each additional argument passed. `format_args!` prepares the
+ /// additional parameters to ensure the output can be interpreted as a string
+ /// and canonicalizes the arguments into a single type. Any value that implements
+ /// the [`Display`] trait can be passed to `format_args!`, as can any
+ /// [`Debug`] implementation be passed to a `{:?}` within the formatting string.
+ ///
/// This macro produces a value of type [`fmt::Arguments`]. This value can be
- /// passed to the functions in [`std::fmt`] for performing useful functions.
+ /// passed to the macros within [`std::fmt`] for performing useful redirection.
/// All other formatting macros ([`format!`], [`write!`], [`println!`], etc) are
- /// proxied through this one.
+ /// proxied through this one. `format_args!`, unlike its derived macros, avoids
+ /// heap allocations.
///
/// For more information, see the documentation in [`std::fmt`].
///
+ /// [`Display`]: ../std/fmt/trait.Display.html
+ /// [`Debug`]: ../std/fmt/trait.Debug.html
/// [`fmt::Arguments`]: ../std/fmt/struct.Arguments.html
/// [`std::fmt`]: ../std/fmt/index.html
/// [`format!`]: ../std/macro.format.html
@@ -219,9 +350,10 @@ pub mod builtin {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[macro_export]
- macro_rules! format_args { ($fmt:expr, $($args:tt)*) => ({
- /* compiler built-in */
- }) }
+ macro_rules! format_args {
+ ($fmt:expr) => ({ /* compiler built-in */ });
+ ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ });
+ }
/// Inspect an environment variable at compile time.
///
@@ -229,9 +361,11 @@ pub mod builtin {
/// compile time, yielding an expression of type `&'static str`.
///
/// If the environment variable is not defined, then a compilation error
- /// will be emitted. To not emit a compile error, use the `option_env!`
+ /// will be emitted. To not emit a compile error, use the [`option_env!`]
/// macro instead.
///
+ /// [`option_env!`]: ../std/macro.option_env.html
+ ///
/// # Examples
///
/// ```
@@ -240,18 +374,24 @@ pub mod builtin {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[macro_export]
- macro_rules! env { ($name:expr) => ({ /* compiler built-in */ }) }
+ macro_rules! env {
+ ($name:expr) => ({ /* compiler built-in */ });
+ ($name:expr,) => ({ /* compiler built-in */ });
+ }
/// Optionally inspect an environment variable at compile time.
///
/// If the named environment variable is present at compile time, this will
/// expand into an expression of type `Option<&'static str>` whose value is
/// `Some` of the value of the environment variable. If the environment
- /// variable is not present, then this will expand to `None`.
+ /// variable is not present, then this will expand to `None`. See
+ /// [`Option<T>`][option] for more information on this type.
///
/// A compile time error is never emitted when using this macro regardless
/// of whether the environment variable is present or not.
///
+ /// [option]: ../std/option/enum.Option.html
+ ///
/// # Examples
///
/// ```
@@ -289,7 +429,8 @@ pub mod builtin {
#[unstable(feature = "concat_idents_macro", issue = "29599")]
#[macro_export]
macro_rules! concat_idents {
- ($($e:ident),*) => ({ /* compiler built-in */ })
+ ($($e:ident),*) => ({ /* compiler built-in */ });
+ ($($e:ident,)*) => ({ /* compiler built-in */ });
}
/// Concatenates literals into a static string slice.
@@ -309,13 +450,25 @@ pub mod builtin {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[macro_export]
- macro_rules! concat { ($($e:expr),*) => ({ /* compiler built-in */ }) }
+ macro_rules! concat {
+ ($($e:expr),*) => ({ /* compiler built-in */ });
+ ($($e:expr,)*) => ({ /* compiler built-in */ });
+ }
/// A macro which expands to the line number on which it was invoked.
///
- /// The expanded expression has type `u32`, and the returned line is not
- /// the invocation of the `line!()` macro itself, but rather the first macro
- /// invocation leading up to the invocation of the `line!()` macro.
+ /// With [`column!`] and [`file!`], these macros provide debugging information for
+ /// developers about the location within the source.
+ ///
+ /// The expanded expression has type `u32` and is 1-based, so the first line
+ /// in each file evaluates to 1, the second to 2, etc. This is consistent
+ /// with error messages by common compilers or popular editors.
+ /// The returned line is not the invocation of the `line!` macro itself,
+ /// but rather the first macro invocation leading up to the invocation
+ /// of the `line!` macro.
+ ///
+ /// [`column!`]: macro.column.html
+ /// [`file!`]: macro.file.html
///
/// # Examples
///
@@ -329,9 +482,18 @@ pub mod builtin {
/// A macro which expands to the column number on which it was invoked.
///
- /// The expanded expression has type `u32`, and the returned column is not
- /// the invocation of the `column!()` macro itself, but rather the first macro
- /// invocation leading up to the invocation of the `column!()` macro.
+ /// With [`line!`] and [`file!`], these macros provide debugging information for
+ /// developers about the location within the source.
+ ///
+ /// The expanded expression has type `u32` and is 1-based, so the first column
+ /// in each line evaluates to 1, the second to 2, etc. This is consistent
+ /// with error messages by common compilers or popular editors.
+ /// The returned column is not the invocation of the `column!` macro itself,
+ /// but rather the first macro invocation leading up to the invocation
+ /// of the `column!` macro.
+ ///
+ /// [`line!`]: macro.line.html
+ /// [`file!`]: macro.file.html
///
/// # Examples
///
@@ -345,11 +507,18 @@ pub mod builtin {
/// A macro which expands to the file name from which it was invoked.
///
+ /// With [`line!`] and [`column!`], these macros provide debugging information for
+ /// developers about the location within the source.
+ ///
+ ///
/// The expanded expression has type `&'static str`, and the returned file
- /// is not the invocation of the `file!()` macro itself, but rather the
- /// first macro invocation leading up to the invocation of the `file!()`
+ /// is not the invocation of the `file!` macro itself, but rather the
+ /// first macro invocation leading up to the invocation of the `file!`
/// macro.
///
+ /// [`line!`]: macro.line.html
+ /// [`column!`]: macro.column.html
+ ///
/// # Examples
///
/// ```
@@ -360,7 +529,7 @@ pub mod builtin {
#[macro_export]
macro_rules! file { () => ({ /* compiler built-in */ }) }
- /// A macro which stringifies its argument.
+ /// A macro which stringifies its arguments.
///
/// This macro will yield an expression of type `&'static str` which is the
/// stringification of all the tokens passed to the macro. No restrictions
@@ -377,7 +546,7 @@ pub mod builtin {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[macro_export]
- macro_rules! stringify { ($t:tt) => ({ /* compiler built-in */ }) }
+ macro_rules! stringify { ($($t:tt)*) => ({ /* compiler built-in */ }) }
/// Includes a utf8-encoded file as a string.
///
@@ -389,9 +558,26 @@ pub mod builtin {
///
/// # Examples
///
- /// ```rust,ignore
- /// let secret_key = include_str!("secret-key.ascii");
+ /// Assume there are two files in the same directory with the following
+ /// contents:
+ ///
+ /// File 'spanish.in':
+ ///
+ /// ```text
+ /// adiós
/// ```
+ ///
+ /// File 'main.rs':
+ ///
+ /// ```ignore (cannot-doctest-external-file-dependency)
+ /// fn main() {
+ /// let my_str = include_str!("spanish.in");
+ /// assert_eq!(my_str, "adiós\n");
+ /// print!("{}", my_str);
+ /// }
+ /// ```
+ ///
+ /// Compiling 'main.rs' and running the resulting binary will print "adiós".
#[stable(feature = "rust1", since = "1.0.0")]
#[macro_export]
macro_rules! include_str { ($file:expr) => ({ /* compiler built-in */ }) }
@@ -406,9 +592,26 @@ pub mod builtin {
///
/// # Examples
///
- /// ```rust,ignore
- /// let secret_key = include_bytes!("secret-key.bin");
+ /// Assume there are two files in the same directory with the following
+ /// contents:
+ ///
+ /// File 'spanish.in':
+ ///
+ /// ```text
+ /// adiós
/// ```
+ ///
+ /// File 'main.rs':
+ ///
+ /// ```ignore (cannot-doctest-external-file-dependency)
+ /// fn main() {
+ /// let bytes = include_bytes!("spanish.in");
+ /// assert_eq!(bytes, b"adi\xc3\xb3s\n");
+ /// print!("{}", String::from_utf8_lossy(bytes));
+ /// }
+ /// ```
+ ///
+ /// Compiling 'main.rs' and running the resulting binary will print "adiós".
#[stable(feature = "rust1", since = "1.0.0")]
#[macro_export]
macro_rules! include_bytes { ($file:expr) => ({ /* compiler built-in */ }) }
@@ -434,14 +637,14 @@ pub mod builtin {
#[macro_export]
macro_rules! module_path { () => ({ /* compiler built-in */ }) }
- /// Boolean evaluation of configuration flags.
+ /// Boolean evaluation of configuration flags, at compile-time.
///
/// In addition to the `#[cfg]` attribute, this macro is provided to allow
/// boolean expression evaluation of configuration flags. This frequently
/// leads to less duplicated code.
///
/// The syntax given to this macro is the same syntax as [the `cfg`
- /// attribute](../reference.html#conditional-compilation).
+ /// attribute](../book/first-edition/conditional-compilation.html).
///
/// # Examples
///
@@ -458,24 +661,80 @@ pub mod builtin {
/// Parse a file as an expression or an item according to the context.
///
- /// The file is located relative to the current file. (similarly to how
- /// modules are found)
+ /// The file is located relative to the current file (similarly to how
+ /// modules are found).
///
/// Using this macro is often a bad idea, because if the file is
/// parsed as an expression, it is going to be placed in the
- /// surrounding code unhygenically. This could result in variables
+ /// surrounding code unhygienically. This could result in variables
/// or functions being different from what the file expected if
/// there are variables or functions that have the same name in
/// the current file.
///
/// # Examples
///
- /// ```ignore
- /// fn foo() {
- /// include!("/path/to/a/file")
+ /// Assume there are two files in the same directory with the following
+ /// contents:
+ ///
+ /// File 'monkeys.in':
+ ///
+ /// ```ignore (only-for-syntax-highlight)
+ /// ['🙈', '🙊', '🙉']
+ /// .iter()
+ /// .cycle()
+ /// .take(6)
+ /// .collect::<String>()
+ /// ```
+ ///
+ /// File 'main.rs':
+ ///
+ /// ```ignore (cannot-doctest-external-file-dependency)
+ /// fn main() {
+ /// let my_string = include!("monkeys.in");
+ /// assert_eq!("🙈🙊🙉🙈🙊🙉", my_string);
+ /// println!("{}", my_string);
/// }
/// ```
+ ///
+ /// Compiling 'main.rs' and running the resulting binary will print
+ /// "🙈🙊🙉🙈🙊🙉".
#[stable(feature = "rust1", since = "1.0.0")]
#[macro_export]
macro_rules! include { ($file:expr) => ({ /* compiler built-in */ }) }
}
+
+/// A macro for defining #[cfg] if-else statements.
+///
+/// This is similar to the `if/elif` C preprocessor macro by allowing definition
+/// of a cascade of `#[cfg]` cases, emitting the implementation which matches
+/// first.
+///
+/// This allows you to conveniently provide a long list #[cfg]'d blocks of code
+/// without having to rewrite each clause multiple times.
+macro_rules! cfg_if {
+ ($(
+ if #[cfg($($meta:meta),*)] { $($it:item)* }
+ ) else * else {
+ $($it2:item)*
+ }) => {
+ __cfg_if_items! {
+ () ;
+ $( ( ($($meta),*) ($($it)*) ), )*
+ ( () ($($it2)*) ),
+ }
+ }
+}
+
+macro_rules! __cfg_if_items {
+ (($($not:meta,)*) ; ) => {};
+ (($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => {
+ __cfg_if_apply! { cfg(all(not(any($($not),*)), $($m,)*)), $($it)* }
+ __cfg_if_items! { ($($not,)* $($m,)*) ; $($rest)* }
+ }
+}
+
+macro_rules! __cfg_if_apply {
+ ($m:meta, $($it:item)*) => {
+ $(#[$m] $it)*
+ }
+}