You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

382 lines
10KB

  1. #![allow(unused)]
  2. //#![recursion_limit = "1000000000"]
  3. //! # Examples
  4. //!
  5. //! ```compile_fail
  6. //! macro_rules! ah_ah_ah_didnt_say_the_magic_word {
  7. //! ($x:ident) => {
  8. //! let x_mut_1 = &mut $x;
  9. //! let x_mut_2 = &mut $x;
  10. //! *x_mut_1 += 1i32;
  11. //! }
  12. //! }
  13. //! let mut x: i32 = 0;
  14. //! ah_ah_ah_didnt_say_the_magic_word!(x);
  15. //! ```
  16. //!
  17. //! Generic `min` won't compile:
  18. //!
  19. //! ```compile_fail
  20. //! fn min<T>(a: T, b: T) -> T {
  21. //! if a < b { a } else { b }
  22. //! }
  23. //! ```
  24. //!
  25. //! ```compile_fail
  26. //! macro_rules! add_one { ($x:ident) => { $x + 1i32 } }
  27. //! let b: std::collections::HashMap<String, u32> = Default::default();
  28. //! add_one!(b);
  29. //! ```
  30. //!
  31. //! ```compile_fail
  32. //! macro_rules! add_one { ($x:ident) => { $x + 1i32 } }
  33. //! add_one(42i32);
  34. //! ```
  35. //!
  36. //! ```compile_fail
  37. //! macro_rules! make_adder_fn {
  38. //! ($n:expr) => {
  39. //! fn add_$n(rhs: i32) -> i32 {
  40. //! $n + rhs
  41. //! }
  42. //! }
  43. //! }
  44. //! make_adder_fn!(42);
  45. //! ```
  46. //!
  47. pub mod case_study;
  48. #[allow(unused)]
  49. #[cfg(test)]
  50. mod tests {
  51. #[test]
  52. fn a_bunch_of_print_lns_showing_var_args() {
  53. println!();
  54. println!("{}", 1);
  55. println!("{} {}", 1, 2);
  56. println!("{} {} {}", 1, 2, 3);
  57. }
  58. #[test]
  59. fn shows_vec_macro_and_its_equivalent() {
  60. let xs: Vec<i32> = vec![1, 2, 3];
  61. let ys: Vec<i32> = {
  62. let mut out = Vec::with_capacity(3);
  63. out.push(1);
  64. out.push(2);
  65. out.push(3);
  66. out
  67. };
  68. assert_eq!(xs, ys);
  69. }
  70. #[test]
  71. fn macro_that_if_used_would_generate_illegal_code_is_itself_not_illegal() {
  72. macro_rules! ah_ah_ah_didnt_say_the_magic_word {
  73. ($x:ident) => {
  74. let x_mut_1 = &mut $x;
  75. let x_mut_2 = &mut $x;
  76. *x_mut_1 += 1i32;
  77. }
  78. }
  79. }
  80. #[test]
  81. fn generic_max_macro_compiles_and_works() {
  82. macro_rules! max {
  83. ($a:expr, $b:expr) => {
  84. if $a > $b { $a } else { $b }
  85. }
  86. }
  87. let a: usize = 1;
  88. let b: usize = 2;
  89. assert_eq!(max!(a, b), 2);
  90. let c = f64::INFINITY;
  91. let d = f64::NEG_INFINITY;
  92. assert_eq!(max!(c, d), f64::INFINITY);
  93. }
  94. #[test]
  95. fn min_with_partial_ord_will_compile() {
  96. fn min_that_compiles<T: PartialOrd>(a: T, b: T) -> T {
  97. if a < b { a } else { b }
  98. }
  99. let a: usize = 1;
  100. let b: usize = 2;
  101. assert_eq!(min_that_compiles(a, b), 1);
  102. }
  103. #[test]
  104. fn generated_type_errors_the_example_of_something_that_works() {
  105. macro_rules! add_one {
  106. ($x:ident) => {
  107. $x + 1i32
  108. }
  109. }
  110. let a: i32 = 42;
  111. assert_eq!(add_one!(a), 43); // Ok: expands to i32 + i32
  112. }
  113. #[test]
  114. fn im_curious_if_a_randomly_chosen_example_from_little_quote_unquote_black_book_compiles() {
  115. macro_rules! abacus {
  116. ((- $($moves:tt)*) -> (+ $($count:tt)*)) => {
  117. abacus!(($($moves)*) -> ($($count)*))
  118. };
  119. ((- $($moves:tt)*) -> ($($count:tt)*)) => {
  120. abacus!(($($moves)*) -> (- $($count)*))
  121. };
  122. ((+ $($moves:tt)*) -> (- $($count:tt)*)) => {
  123. abacus!(($($moves)*) -> ($($count)*))
  124. };
  125. ((+ $($moves:tt)*) -> ($($count:tt)*)) => {
  126. abacus!(($($moves)*) -> (+ $($count)*))
  127. };
  128. // Check if the final result is zero.
  129. (() -> ()) => { true };
  130. (() -> ($($count:tt)+)) => { false };
  131. }
  132. // this one never finishes
  133. //macro_rules! abacus2 {
  134. // (-) => {-1};
  135. // (+) => {1};
  136. // ($($moves:tt)*) => {
  137. // 0 $(+ abacus2!($moves))*
  138. // }
  139. //}
  140. let equals_zero = abacus!((++-+-+++--++---++----+) -> ());
  141. assert_eq!(equals_zero, true);
  142. //let equals_zero = abacus2!((++-+-+++--++---++----+) -> ());
  143. //assert_eq!(equals_zero, true);
  144. }
  145. #[test]
  146. fn how_about_this_example_from_little_book() {
  147. macro_rules! parse_unitary_variants {
  148. (@as_expr $e:expr) => {$e};
  149. (@as_item $($i:item)+) => {$($i)+};
  150. // Exit rules.
  151. (
  152. @collect_unitary_variants ($callback:ident ( $($args:tt)* )),
  153. ($(,)*) -> ($($var_names:ident,)*)
  154. ) => {
  155. parse_unitary_variants! {
  156. @as_expr
  157. $callback!{ $($args)* ($($var_names),*) }
  158. }
  159. };
  160. (
  161. @collect_unitary_variants ($callback:ident { $($args:tt)* }),
  162. ($(,)*) -> ($($var_names:ident,)*)
  163. ) => {
  164. parse_unitary_variants! {
  165. @as_item
  166. $callback!{ $($args)* ($($var_names),*) }
  167. }
  168. };
  169. // Consume an attribute.
  170. (
  171. @collect_unitary_variants $fixed:tt,
  172. (#[$_attr:meta] $($tail:tt)*) -> ($($var_names:tt)*)
  173. ) => {
  174. parse_unitary_variants! {
  175. @collect_unitary_variants $fixed,
  176. ($($tail)*) -> ($($var_names)*)
  177. }
  178. };
  179. // Handle a variant, optionally with an with initialiser.
  180. (
  181. @collect_unitary_variants $fixed:tt,
  182. ($var:ident $(= $_val:expr)*, $($tail:tt)*) -> ($($var_names:tt)*)
  183. ) => {
  184. parse_unitary_variants! {
  185. @collect_unitary_variants $fixed,
  186. ($($tail)*) -> ($($var_names)* $var,)
  187. }
  188. };
  189. // Abort on variant with a payload.
  190. (
  191. @collect_unitary_variants $fixed:tt,
  192. ($var:ident $_struct:tt, $($tail:tt)*) -> ($($var_names:tt)*)
  193. ) => {
  194. const _error: () = "cannot parse unitary variants from enum with non-unitary variants";
  195. };
  196. // Entry rule.
  197. (enum $name:ident {$($body:tt)*} => $callback:ident $arg:tt) => {
  198. parse_unitary_variants! {
  199. @collect_unitary_variants
  200. ($callback $arg), ($($body)*,) -> ()
  201. }
  202. };
  203. }
  204. /*
  205. not sure how to invoke this one
  206. let mut variants: Vec<&'static str> = Vec::new();
  207. macro_rules! get_unitary_variant_str {
  208. {() ($($var_names),*) } => { $( variants.push(stringify!($variant)); )* }
  209. }
  210. parse_unitary_variants!(
  211. enum Abcs {
  212. A,
  213. B,
  214. C,
  215. D,
  216. E
  217. } => get_unitary_variant_str ()
  218. );
  219. */
  220. }
  221. #[test]
  222. fn tt_muncher() {
  223. macro_rules! mixed_rules {
  224. () => {};
  225. (trace $name:ident; $($tail:tt)*) => {
  226. {
  227. println!(concat!(stringify!($name), " = {:?}"), $name);
  228. mixed_rules!($($tail)*);
  229. }
  230. };
  231. (trace $name:ident = $init:expr; $($tail:tt)*) => {
  232. {
  233. let $name = $init;
  234. println!(concat!(stringify!($name), " = {:?}"), $name);
  235. mixed_rules!($($tail)*);
  236. }
  237. };
  238. }
  239. mixed_rules!(trace x = 1;);
  240. }
  241. use std::fmt::Display;
  242. fn i_need_display_not_debug<T: Display>(x: T) -> String {
  243. format!("{}", x)
  244. }
  245. #[test]
  246. fn debug_display_macro_actually_works() {
  247. #[derive(Debug)]
  248. struct Point {
  249. pub x: f64,
  250. pub y: f64,
  251. }
  252. macro_rules! debug_display {
  253. ($t:ident) => {
  254. impl std::fmt::Display for $t {
  255. fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
  256. write!(f, "{:?}", self)
  257. }
  258. }
  259. }
  260. }
  261. debug_display!(Point); // poof! it implements Display
  262. let p = Point { x: 1.234, y: 2.345 };
  263. i_need_display_not_debug(p);
  264. }
  265. #[test]
  266. fn example_for_why_you_should_use_fully_qualified_names() {
  267. pub struct A;
  268. pub trait Devious {
  269. fn abc(&self) -> isize { 42 }
  270. fn xyz(&self) -> isize { 42 }
  271. }
  272. impl Devious for A {}
  273. let a = A;
  274. macro_rules! didnt_see_it_coming {
  275. { $x:ident ;; } => {
  276. <A as Devious>::xyz(&$x)
  277. };
  278. { $x:ident <-> } => {
  279. <A as Devious>::abc(&$x)
  280. }
  281. }
  282. //let c = <A as ::tests::example_for_why_you_should_use_fully_qualified_names::Devious>::abc(&a);
  283. //macro_rules! you_gotta_be_wiser {
  284. // { [[ $x:ident ]] } => {
  285. // <A as ::tests::example_for_why_you_should_use_fully_qualified_names::Devious>::abc(&$x)
  286. // }
  287. // //{ [[ $x:ident ]] } => {
  288. // // <A as crate::tests::example_for_why_you_should_use_fully_qualified_names::Devious>::abc(&$x)
  289. // //};
  290. // //{ -^-^- $x:ident -^-^- } => {{
  291. // // // invoking the version that's inside `the_upside_down`
  292. // // use crate::tests::example_for_why_you_should_use_fully_qualified_names::the_upside_down::Devious as OtherDevious;
  293. // // <A as crate::tests::example_for_why_you_should_use_fully_qualified_names::the_upside_down::OtherDevious>::xyz(&$x)
  294. // //}};
  295. //}
  296. assert_eq!(didnt_see_it_coming!{ a <-> }, 42);
  297. //assert_eq!(you_gotta_be_wiser!{ [[ a ]] }, 42);
  298. //assert_eq!(you_gotta_be_wiser!{ -^-^- a -^-^- }, -42);
  299. /// muhaha
  300. fn the_upside_down(a: &A) -> isize {
  301. /// we have our own 'Devious' down here...
  302. pub trait Devious {
  303. fn abc(&self) -> isize { -42 }
  304. fn xyz(&self) -> isize { -42 }
  305. }
  306. impl Devious for A {}
  307. didnt_see_it_coming!{ a ;; }
  308. }
  309. assert_eq!(the_upside_down(&a), -42);
  310. }
  311. #[test]
  312. fn make_adder_with_supplied_name_working_example() {
  313. macro_rules! make_adder_fn {
  314. ($f:ident, $n:expr) => {
  315. fn $f(rhs: i32) -> i32 {
  316. $n + rhs
  317. }
  318. }
  319. }
  320. make_adder_fn!(add_42, 42);
  321. assert_eq!(add_42(0), 42);
  322. assert_eq!(add_42(42), 84);
  323. }
  324. }