Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Function-like macros

Function-like macros are that are used like declarative macros and can take any valid token stream input. They take a TokenStream as input, and output a TokenStream.

They have the following signature:

#![allow(unused)]
fn main() {
#[proc_macro]
pub fn my_macro(input: TokenStream) -> TokenStream {
  ...
}
}

This macro can then be used in code as such:

#![allow(unused)]
fn main() {
my_macro_crate::my_macro!(...);
}

As an example, lets make a macro that takes an identifier, and a literal and create a constant for us:

#![allow(unused)]
fn main() {
use proc_macro::TokenStream;

/// The ParsedInput structure will be used to store the input to our macros.
struct ParsedInput
{
  /// Identifier for the generated constant.
  ident: syn::Ident,
  /// String expression.
  expr: syn::LitStr,
}

/// Implement the Parse trait from syn to parse the input
impl syn::parse::Parse for ParsedInput
{
  fn parse(input: syn::parse::ParseStream) -> syn::Result<Self>
  {
    // Parse our first macro argument, the identifier.
    let ident = input.parse()?;
    // Parse the comma and ignore it.
    let _: syn::Token![,] = input.parse()?;
    // Parse our second macro argument, the string expression.
    let expr = input.parse()?;
    Ok(Self { ident, expr })
  }
}

#[proc_macro]
pub fn make_constant(input: TokenStream) -> TokenStream
{
  let ParsedInput { ident, expr } = syn::parse_macro_input!(input as ParsedInput);
  // Use the quote crate to create the constant.
  quote::quote! {
    const #ident: &str = #expr;
  }
  .into()
}
}