#![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(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 = 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 = vec![1, 2, 3]; let ys: Vec = { 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(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(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 ;; } => { ::xyz(&$x) }; { $x:ident <-> } => { ::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); } }