|
- #![allow(unused)]
- //#![recursion_limit = "1000000000"]
-
- //! # Examples
- //!
- //! ```compile_fail
- //! macro_rules! ah_ah_ah_didnt_say_the_magic_word {
- //! ($x:ident) => {
- //! let x_mut_1 = &mut $x;
- //! let x_mut_2 = &mut $x;
- //! *x_mut_1 += 1i32;
- //! }
- //! }
- //! let mut x: i32 = 0;
- //! ah_ah_ah_didnt_say_the_magic_word!(x);
- //! ```
- //!
- //! Generic `min` won't compile:
- //!
- //! ```compile_fail
- //! fn min<T>(a: T, b: T) -> T {
- //! if a < b { a } else { b }
- //! }
- //! ```
- //!
- //! ```compile_fail
- //! macro_rules! add_one { ($x:ident) => { $x + 1i32 } }
- //! let b: std::collections::HashMap<String, u32> = Default::default();
- //! add_one!(b);
- //! ```
- //!
- //! ```compile_fail
- //! macro_rules! add_one { ($x:ident) => { $x + 1i32 } }
- //! add_one(42i32);
- //! ```
- //!
- //! ```compile_fail
- //! macro_rules! make_adder_fn {
- //! ($n:expr) => {
- //! fn add_$n(rhs: i32) -> i32 {
- //! $n + rhs
- //! }
- //! }
- //! }
- //! make_adder_fn!(42);
- //! ```
-
- #[cfg(test)]
- mod tests {
-
- #[test]
- fn a_bunch_of_print_lns_showing_var_args() {
- println!();
- println!("{}", 1);
- println!("{} {}", 1, 2);
- println!("{} {} {}", 1, 2, 3);
- }
-
- #[test]
- fn shows_vec_macro_and_its_equivalent() {
- let xs: Vec<i32> = vec![1, 2, 3];
- let ys: Vec<i32> = {
- let mut out = Vec::with_capacity(3);
- out.push(1);
- out.push(2);
- out.push(3);
- out
- };
- assert_eq!(xs, ys);
- }
-
- #[test]
- fn macro_that_if_used_would_generate_illegal_code_is_itself_not_illegal() {
- macro_rules! ah_ah_ah_didnt_say_the_magic_word {
- ($x:ident) => {
- let x_mut_1 = &mut $x;
- let x_mut_2 = &mut $x;
- *x_mut_1 += 1i32;
- }
- }
- }
-
- #[test]
- fn generic_max_macro_compiles_and_works() {
- macro_rules! max {
- ($a:expr, $b:expr) => {
- if $a > $b { $a } else { $b }
- }
- }
-
- let a: usize = 1;
- let b: usize = 2;
- assert_eq!(max!(a, b), 2);
-
- let c = f64::INFINITY;
- let d = f64::NEG_INFINITY;
- assert_eq!(max!(c, d), f64::INFINITY);
- }
-
- #[test]
- fn min_with_partial_ord_will_compile() {
- fn min_that_compiles<T: PartialOrd>(a: T, b: T) -> T {
- if a < b { a } else { b }
- }
- let a: usize = 1;
- let b: usize = 2;
- assert_eq!(min_that_compiles(a, b), 1);
- }
-
- #[test]
- fn generated_type_errors_the_example_of_something_that_works() {
- macro_rules! add_one {
- ($x:ident) => {
- $x + 1i32
- }
- }
- let a: i32 = 42;
-
- assert_eq!(add_one!(a), 43); // Ok: expands to i32 + i32
- }
-
- #[test]
- fn im_curious_if_a_randomly_chosen_example_from_little_quote_unquote_black_book_compiles() {
- macro_rules! abacus {
- ((- $($moves:tt)*) -> (+ $($count:tt)*)) => {
- abacus!(($($moves)*) -> ($($count)*))
- };
- ((- $($moves:tt)*) -> ($($count:tt)*)) => {
- abacus!(($($moves)*) -> (- $($count)*))
- };
- ((+ $($moves:tt)*) -> (- $($count:tt)*)) => {
- abacus!(($($moves)*) -> ($($count)*))
- };
- ((+ $($moves:tt)*) -> ($($count:tt)*)) => {
- abacus!(($($moves)*) -> (+ $($count)*))
- };
-
- // Check if the final result is zero.
- (() -> ()) => { true };
- (() -> ($($count:tt)+)) => { false };
- }
-
- // this one never finishes
- //macro_rules! abacus2 {
- // (-) => {-1};
- // (+) => {1};
- // ($($moves:tt)*) => {
- // 0 $(+ abacus2!($moves))*
- // }
- //}
-
- let equals_zero = abacus!((++-+-+++--++---++----+) -> ());
- assert_eq!(equals_zero, true);
-
- //let equals_zero = abacus2!((++-+-+++--++---++----+) -> ());
- //assert_eq!(equals_zero, true);
- }
-
- #[test]
- fn how_about_this_example_from_little_book() {
- macro_rules! parse_unitary_variants {
- (@as_expr $e:expr) => {$e};
- (@as_item $($i:item)+) => {$($i)+};
-
- // Exit rules.
- (
- @collect_unitary_variants ($callback:ident ( $($args:tt)* )),
- ($(,)*) -> ($($var_names:ident,)*)
- ) => {
- parse_unitary_variants! {
- @as_expr
- $callback!{ $($args)* ($($var_names),*) }
- }
- };
-
- (
- @collect_unitary_variants ($callback:ident { $($args:tt)* }),
- ($(,)*) -> ($($var_names:ident,)*)
- ) => {
- parse_unitary_variants! {
- @as_item
- $callback!{ $($args)* ($($var_names),*) }
- }
- };
-
- // Consume an attribute.
- (
- @collect_unitary_variants $fixed:tt,
- (#[$_attr:meta] $($tail:tt)*) -> ($($var_names:tt)*)
- ) => {
- parse_unitary_variants! {
- @collect_unitary_variants $fixed,
- ($($tail)*) -> ($($var_names)*)
- }
- };
-
- // Handle a variant, optionally with an with initialiser.
- (
- @collect_unitary_variants $fixed:tt,
- ($var:ident $(= $_val:expr)*, $($tail:tt)*) -> ($($var_names:tt)*)
- ) => {
- parse_unitary_variants! {
- @collect_unitary_variants $fixed,
- ($($tail)*) -> ($($var_names)* $var,)
- }
- };
-
- // Abort on variant with a payload.
- (
- @collect_unitary_variants $fixed:tt,
- ($var:ident $_struct:tt, $($tail:tt)*) -> ($($var_names:tt)*)
- ) => {
- const _error: () = "cannot parse unitary variants from enum with non-unitary variants";
- };
-
- // Entry rule.
- (enum $name:ident {$($body:tt)*} => $callback:ident $arg:tt) => {
- parse_unitary_variants! {
- @collect_unitary_variants
- ($callback $arg), ($($body)*,) -> ()
- }
- };
- }
-
- /*
-
- not sure how to invoke this one
-
- let mut variants: Vec<&'static str> = Vec::new();
-
- macro_rules! get_unitary_variant_str {
- {() ($($var_names),*) } => { $( variants.push(stringify!($variant)); )* }
- }
-
- parse_unitary_variants!(
- enum Abcs {
- A,
- B,
- C,
- D,
- E
- } => get_unitary_variant_str ()
- );
- */
- }
-
- #[test]
- fn tt_muncher() {
- macro_rules! mixed_rules {
- () => {};
- (trace $name:ident; $($tail:tt)*) => {
- {
- println!(concat!(stringify!($name), " = {:?}"), $name);
- mixed_rules!($($tail)*);
- }
- };
- (trace $name:ident = $init:expr; $($tail:tt)*) => {
- {
- let $name = $init;
- println!(concat!(stringify!($name), " = {:?}"), $name);
- mixed_rules!($($tail)*);
- }
- };
- }
-
- mixed_rules!(trace x = 1;);
- }
-
- use std::fmt::Display;
-
- fn i_need_display_not_debug<T: Display>(x: T) -> String {
- format!("{}", x)
- }
-
- #[test]
- fn debug_display_macro_actually_works() {
- #[derive(Debug)]
- struct Point {
- pub x: f64,
- pub y: f64,
- }
-
- macro_rules! debug_display {
- ($t:ident) => {
- impl std::fmt::Display for $t {
- fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
- write!(f, "{:?}", self)
- }
- }
- }
- }
-
- debug_display!(Point); // poof! it implements Display
-
- let p = Point { x: 1.234, y: 2.345 };
-
- i_need_display_not_debug(p);
- }
-
- #[test]
- fn example_for_why_you_should_use_fully_qualified_names() {
- struct A;
-
- trait Devious {
- fn abc(&self) -> isize { 42 }
- fn xyz(&self) -> isize { 42 }
- }
-
- impl Devious for A {}
-
- let a = A;
-
- macro_rules! didnt_see_it_coming {
- { $x:ident ;; } => {
- <A as Devious>::xyz(&$x)
- };
-
- { $x:ident <-> } => {
- <A as Devious>::abc(&$x)
- }
- }
-
- assert_eq!(didnt_see_it_coming!{ a <-> }, 42);
-
- /// muhaha
- fn the_upside_down(a: &A) -> isize {
- /// we have our own 'Devious' down here...
- trait Devious {
- fn abc(&self) -> isize { -42 }
- fn xyz(&self) -> isize { -42 }
- }
-
- impl Devious for A {}
-
- didnt_see_it_coming!{ a ;; }
- }
-
- assert_eq!(the_upside_down(&a), -42);
-
- }
-
- }
|