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.

343 lines
9.0KB

  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. #[cfg(test)]
  47. mod tests {
  48. #[test]
  49. fn a_bunch_of_print_lns_showing_var_args() {
  50. println!();
  51. println!("{}", 1);
  52. println!("{} {}", 1, 2);
  53. println!("{} {} {}", 1, 2, 3);
  54. }
  55. #[test]
  56. fn shows_vec_macro_and_its_equivalent() {
  57. let xs: Vec<i32> = vec![1, 2, 3];
  58. let ys: Vec<i32> = {
  59. let mut out = Vec::with_capacity(3);
  60. out.push(1);
  61. out.push(2);
  62. out.push(3);
  63. out
  64. };
  65. assert_eq!(xs, ys);
  66. }
  67. #[test]
  68. fn macro_that_if_used_would_generate_illegal_code_is_itself_not_illegal() {
  69. macro_rules! ah_ah_ah_didnt_say_the_magic_word {
  70. ($x:ident) => {
  71. let x_mut_1 = &mut $x;
  72. let x_mut_2 = &mut $x;
  73. *x_mut_1 += 1i32;
  74. }
  75. }
  76. }
  77. #[test]
  78. fn generic_max_macro_compiles_and_works() {
  79. macro_rules! max {
  80. ($a:expr, $b:expr) => {
  81. if $a > $b { $a } else { $b }
  82. }
  83. }
  84. let a: usize = 1;
  85. let b: usize = 2;
  86. assert_eq!(max!(a, b), 2);
  87. let c = f64::INFINITY;
  88. let d = f64::NEG_INFINITY;
  89. assert_eq!(max!(c, d), f64::INFINITY);
  90. }
  91. #[test]
  92. fn min_with_partial_ord_will_compile() {
  93. fn min_that_compiles<T: PartialOrd>(a: T, b: T) -> T {
  94. if a < b { a } else { b }
  95. }
  96. let a: usize = 1;
  97. let b: usize = 2;
  98. assert_eq!(min_that_compiles(a, b), 1);
  99. }
  100. #[test]
  101. fn generated_type_errors_the_example_of_something_that_works() {
  102. macro_rules! add_one {
  103. ($x:ident) => {
  104. $x + 1i32
  105. }
  106. }
  107. let a: i32 = 42;
  108. assert_eq!(add_one!(a), 43); // Ok: expands to i32 + i32
  109. }
  110. #[test]
  111. fn im_curious_if_a_randomly_chosen_example_from_little_quote_unquote_black_book_compiles() {
  112. macro_rules! abacus {
  113. ((- $($moves:tt)*) -> (+ $($count:tt)*)) => {
  114. abacus!(($($moves)*) -> ($($count)*))
  115. };
  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. // Check if the final result is zero.
  126. (() -> ()) => { true };
  127. (() -> ($($count:tt)+)) => { false };
  128. }
  129. // this one never finishes
  130. //macro_rules! abacus2 {
  131. // (-) => {-1};
  132. // (+) => {1};
  133. // ($($moves:tt)*) => {
  134. // 0 $(+ abacus2!($moves))*
  135. // }
  136. //}
  137. let equals_zero = abacus!((++-+-+++--++---++----+) -> ());
  138. assert_eq!(equals_zero, true);
  139. //let equals_zero = abacus2!((++-+-+++--++---++----+) -> ());
  140. //assert_eq!(equals_zero, true);
  141. }
  142. #[test]
  143. fn how_about_this_example_from_little_book() {
  144. macro_rules! parse_unitary_variants {
  145. (@as_expr $e:expr) => {$e};
  146. (@as_item $($i:item)+) => {$($i)+};
  147. // Exit rules.
  148. (
  149. @collect_unitary_variants ($callback:ident ( $($args:tt)* )),
  150. ($(,)*) -> ($($var_names:ident,)*)
  151. ) => {
  152. parse_unitary_variants! {
  153. @as_expr
  154. $callback!{ $($args)* ($($var_names),*) }
  155. }
  156. };
  157. (
  158. @collect_unitary_variants ($callback:ident { $($args:tt)* }),
  159. ($(,)*) -> ($($var_names:ident,)*)
  160. ) => {
  161. parse_unitary_variants! {
  162. @as_item
  163. $callback!{ $($args)* ($($var_names),*) }
  164. }
  165. };
  166. // Consume an attribute.
  167. (
  168. @collect_unitary_variants $fixed:tt,
  169. (#[$_attr:meta] $($tail:tt)*) -> ($($var_names:tt)*)
  170. ) => {
  171. parse_unitary_variants! {
  172. @collect_unitary_variants $fixed,
  173. ($($tail)*) -> ($($var_names)*)
  174. }
  175. };
  176. // Handle a variant, optionally with an with initialiser.
  177. (
  178. @collect_unitary_variants $fixed:tt,
  179. ($var:ident $(= $_val:expr)*, $($tail:tt)*) -> ($($var_names:tt)*)
  180. ) => {
  181. parse_unitary_variants! {
  182. @collect_unitary_variants $fixed,
  183. ($($tail)*) -> ($($var_names)* $var,)
  184. }
  185. };
  186. // Abort on variant with a payload.
  187. (
  188. @collect_unitary_variants $fixed:tt,
  189. ($var:ident $_struct:tt, $($tail:tt)*) -> ($($var_names:tt)*)
  190. ) => {
  191. const _error: () = "cannot parse unitary variants from enum with non-unitary variants";
  192. };
  193. // Entry rule.
  194. (enum $name:ident {$($body:tt)*} => $callback:ident $arg:tt) => {
  195. parse_unitary_variants! {
  196. @collect_unitary_variants
  197. ($callback $arg), ($($body)*,) -> ()
  198. }
  199. };
  200. }
  201. /*
  202. not sure how to invoke this one
  203. let mut variants: Vec<&'static str> = Vec::new();
  204. macro_rules! get_unitary_variant_str {
  205. {() ($($var_names),*) } => { $( variants.push(stringify!($variant)); )* }
  206. }
  207. parse_unitary_variants!(
  208. enum Abcs {
  209. A,
  210. B,
  211. C,
  212. D,
  213. E
  214. } => get_unitary_variant_str ()
  215. );
  216. */
  217. }
  218. #[test]
  219. fn tt_muncher() {
  220. macro_rules! mixed_rules {
  221. () => {};
  222. (trace $name:ident; $($tail:tt)*) => {
  223. {
  224. println!(concat!(stringify!($name), " = {:?}"), $name);
  225. mixed_rules!($($tail)*);
  226. }
  227. };
  228. (trace $name:ident = $init:expr; $($tail:tt)*) => {
  229. {
  230. let $name = $init;
  231. println!(concat!(stringify!($name), " = {:?}"), $name);
  232. mixed_rules!($($tail)*);
  233. }
  234. };
  235. }
  236. mixed_rules!(trace x = 1;);
  237. }
  238. use std::fmt::Display;
  239. fn i_need_display_not_debug<T: Display>(x: T) -> String {
  240. format!("{}", x)
  241. }
  242. #[test]
  243. fn debug_display_macro_actually_works() {
  244. #[derive(Debug)]
  245. struct Point {
  246. pub x: f64,
  247. pub y: f64,
  248. }
  249. macro_rules! debug_display {
  250. ($t:ident) => {
  251. impl std::fmt::Display for $t {
  252. fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
  253. write!(f, "{:?}", self)
  254. }
  255. }
  256. }
  257. }
  258. debug_display!(Point); // poof! it implements Display
  259. let p = Point { x: 1.234, y: 2.345 };
  260. i_need_display_not_debug(p);
  261. }
  262. #[test]
  263. fn example_for_why_you_should_use_fully_qualified_names() {
  264. struct A;
  265. trait Devious {
  266. fn abc(&self) -> isize { 42 }
  267. fn xyz(&self) -> isize { 42 }
  268. }
  269. impl Devious for A {}
  270. let a = A;
  271. macro_rules! didnt_see_it_coming {
  272. { $x:ident ;; } => {
  273. <A as Devious>::xyz(&$x)
  274. };
  275. { $x:ident <-> } => {
  276. <A as Devious>::abc(&$x)
  277. }
  278. }
  279. assert_eq!(didnt_see_it_coming!{ a <-> }, 42);
  280. /// muhaha
  281. fn the_upside_down(a: &A) -> isize {
  282. /// we have our own 'Devious' down here...
  283. trait Devious {
  284. fn abc(&self) -> isize { -42 }
  285. fn xyz(&self) -> isize { -42 }
  286. }
  287. impl Devious for A {}
  288. didnt_see_it_coming!{ a ;; }
  289. }
  290. assert_eq!(the_upside_down(&a), -42);
  291. }
  292. }