Rust Macros

Written — Updated
  • Useful Links
  • Arguments
    • Macro argument types
      • expr - Any expression
      • ident - An identifier
      • path - A module path
      • ty - A type
      • item - A top level item (use, struct Something{}, etc.)
      • tt - Any token tree
      • block - A code block in brackets
    • Argument patterns can have * or + added to it to indicate repetition.
      • macro_rules! macro {
          ($an_arg: expr, $($num: expr),*) => { 
            let mut x = get_number($an_arg);	
            $(
              x += $num;
         	)* // Wrapping it like this expands the variadic arguments
         	x
          }
        }
        
        
  • Nested macros
    • Macros normally can't call each other if one of the macros is used from another module.
    • But you can create another macro rule in the same macro. Traditionally these rules start with @ to reduce chances of accidentally triggering the rule.
    • macro_rules! macro1 {
        () => { macro1!(@macro2)};
        (@macro2) => { the nested macro }
      }
      
  • Dealing with tokens
    • The paste crate lets you concatenate multiple identifiers into a new identifier, which is difficult to do in normal macros.
  • Proc Macros
    • These are more powerful and are written in Rust.
    • They can be function-like macros as with macro_rules! or attribute macros like #[test], or derive macros to work with #[derive(...)].
    • Since these are effectively compiler plugins, they have to be in a separate crate from the one that uses the macro.
    • Useful Crates
      • syn helps with parsing Rust source.

Thanks for reading! If you have any questions or comments, please send me a note on Twitter.