Macros
Procedural Macros
A procedural macro (proc-macro) is a compiled Rust function that executes at compile time inside the compiler process, receiving an input proc_macro::TokenStream and returning a generated proc_macro::TokenStream.
Why Procedural Macros Require a Dedicated proc-macro Crate
Because procedural macros are compiled into native machine code (a dynamic library / .dylib / .so) and loaded by rustc to run while compiling downstream crates, Cargo requires procedural macros to live in their own crate with proc-macro = true in Cargo.toml:
[package]
name = "my_macros"
version = "0.1.0"
edition = "2024"
[lib]
proc-macro = true
[dependencies]
syn = "2"
quote = "1"
proc-macro2 = "1"
+----------------------------------+
| my_macros (proc-macro = true)|
| Compiled for host architecture |
+-----------------+----------------+
│ Loaded by `rustc` at compile time
▼
+----------------------------------+
| app_crate (normal crate) |
| #[derive(MyTrait)] struct Foo; | ──(TokenStream)──> my_macros ──(Generated impl)──> AST
+----------------------------------+
The Three Kinds of Procedural Macros
| Procedural Macro Kind | Attribute on Definition | Usage Syntax | Input TokenStream(s) |
Output TokenStream |
|---|---|---|---|---|
| 1. Derive Macro | #[proc_macro_derive(Name, attributes(helper))] |
#[derive(Name)] on a struct, enum, or union |
1 (item: the struct/enum tokens) |
Appended after the original struct/enum (never modifies original item) |
| 2. Attribute-Like Macro | #[proc_macro_attribute] |
#[my_attr(args)] on any item (fn, struct, impl, mod) |
2 (attr: attribute args, item: the target item) |
Replaces the target item entirely |
| 3. Function-Like Macro | #[proc_macro] |
my_macro!(tokens) |
1 (input: tokens inside (...)) |
Replaces the macro invocation at the call site |
The Standard Proc-Macro Ecosystem (proc-macro2, syn, quote)
While the compiler's built-in proc_macro crate provides raw TokenTrees (Group, Ident, Punct, Literal), production procedural macros almost always combine three foundational crates:
syn: Parses a rawTokenStreaminto strongly typed Rust AST structs (DeriveInput,ItemFn,Expr).quote: Provides thequote! { ... }quasi-quoting macro that turns Rust syntax with#variableinterpolations back into aTokenStream.proc-macro2: A wrapper aroundproc_macro::TokenStreamthat can be used inside unit tests and regular non-proc-macrolibrary code.