Rust Macro Examples.

Function Macro


macro_rules! funcmacro {
    () => {
        println!("funcmacro");
    };
    ($a: expr, $b: expr) => {
        println!("res: {}", $a + $b);
    }
}

fn main() {
    funcmacro!();
    funcmacro!(1, 2);
}

Run Result

 cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.56s
     Running `target/debug/hello`
funcmacro
res: 3

Attribute Macro

Step 1:

[lib]
proc-macro = true

Step 2:

use hello::*;

#[attrmacro]
fn hello() {}

fn main() {
    hello();
}

Step 3:


use proc_macro::{TokenStream};
use quote::{quote};

#[proc_macro_attribute]
pub fn attrmacro(_metadata: TokenStream, _input: TokenStream) -> TokenStream {
    TokenStream::from(quote!{fn hello() { println!("world")}})
}

Debug Result

#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
use hello::*;
fn hello() {
    {
        ::std::io::_print(::core::fmt::Arguments::new_v1(&["world\n"], &[]));
    }
}
fn main() {
    hello();
}

Run Resut

✗ cargo run
warning: unused manifest key: package.proc-macro
   Compiling hello v0.1.0 (~/rust-examples/hello)
    Finished dev [unoptimized + debuginfo] target(s) in 0.44s
     Running `target/debug/hello`
world

Debug Macro


# 安装 expand
$ cargo install cargo-expand

# 目前仅 nightly 支持
$ rustup install nightly
$ rustup default nightly

# 测试
$ cargo expand --bin hello

Derive Macro

Step 1:


use hello::*;
// drive macro demo

pub trait DeriveMacro {
    fn print();
}

#[derive(DeriveMacro)]
struct MyStruct {}

fn main() {
    MyStruct::print();
}

Step 2:

use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, token::Token, DeriveInput};

#[proc_macro_derive(DeriveMacro)]
pub fn derive_trait(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    let name = input.ident;

    let expanded = quote! {

        impl DeriveMacro for #name {
          fn print() {
            println!("hello from DeriveMacro")
          }
        }
    };

    TokenStream::from(expanded)
}

Run Result

 cargo run
     Running `target/debug/hello`
hello from DeriveMacro

Full Demo

// lib.rs
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, token::Token, DeriveInput};

#[proc_macro_attribute]
pub fn attrmacro(_metadata: TokenStream, _input: TokenStream) -> TokenStream {
    TokenStream::from(quote! {fn hello() { println!("hello from attribute macro")}})
}

#[proc_macro_derive(DeriveMacro)]
pub fn derive_trait(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    let name = input.ident;

    let expanded = quote! {

        impl DeriveMacro for #name {
          fn print() {
            println!("hello from derive macro")
          }
        }
    };

    TokenStream::from(expanded)
}
// main.rs
use hello::*;

macro_rules! funcmacro {
    () => {
        println!("hello from function macro");
    };
    ($a: expr, $b: expr) => {
        println!("hello from function macro res: {}", $a + $b);
    };
}

#[attrmacro]
fn hello() {}


// drive macro demo

pub trait DeriveMacro {
    fn print();
}

#[derive(DeriveMacro)]
struct MyStruct {}

fn main() {
    funcmacro!();
    funcmacro!(1, 2);

    hello();

    MyStruct::print();
}

# Cargo.toml

[package]
name = "hello"
version = "0.1.0"
edition = "2021"
proc-macro = true

[lib]
proc-macro = true

[dependencies]
syn = {version="1.0.57",features=["full","fold"]}
quote = "1.0.8"

Run Result

✗ cargo run
hello from function macro
hello from function macro res: 3
hello from attribute macro
hello from derive macro

References