<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://johnwick.cc/index.php?action=history&amp;feed=atom&amp;title=Inside_Rust%E2%80%99s_Meta-Programming_Revolution%3A_Macros_2.0</id>
	<title>Inside Rust’s Meta-Programming Revolution: Macros 2.0 - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://johnwick.cc/index.php?action=history&amp;feed=atom&amp;title=Inside_Rust%E2%80%99s_Meta-Programming_Revolution%3A_Macros_2.0"/>
	<link rel="alternate" type="text/html" href="https://johnwick.cc/index.php?title=Inside_Rust%E2%80%99s_Meta-Programming_Revolution:_Macros_2.0&amp;action=history"/>
	<updated>2026-05-07T02:35:28Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.44.1</generator>
	<entry>
		<id>https://johnwick.cc/index.php?title=Inside_Rust%E2%80%99s_Meta-Programming_Revolution:_Macros_2.0&amp;diff=332&amp;oldid=prev</id>
		<title>PC: Created page with &quot;500px  “Wait, Rust Has Macros?”  If you’re new to Rust, the word macro probably evokes flashbacks to C’s preprocessor nightmares — #define spaghetti, double-evaluated expressions, and impossible-to-debug expansions. But Rust’s macros are nothing like that. They’re not dumb text substitution engines.  They’re syntactic transformers — fully aware of types, scopes, and syntax trees. And with Macros 2.0, Rust is...&quot;</title>
		<link rel="alternate" type="text/html" href="https://johnwick.cc/index.php?title=Inside_Rust%E2%80%99s_Meta-Programming_Revolution:_Macros_2.0&amp;diff=332&amp;oldid=prev"/>
		<updated>2025-11-17T15:27:48Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;&lt;a href=&quot;/index.php?title=File:Inside_Rust%E2%80%99s_Meta.jpg&quot; title=&quot;File:Inside Rust’s Meta.jpg&quot;&gt;500px&lt;/a&gt;  “Wait, Rust Has Macros?”  If you’re new to Rust, the word macro probably evokes flashbacks to C’s preprocessor nightmares — #define spaghetti, double-evaluated expressions, and impossible-to-debug expansions. But Rust’s macros are nothing like that. They’re not dumb text substitution engines.  They’re syntactic transformers — fully aware of types, scopes, and syntax trees. And with Macros 2.0, Rust is...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;[[file:Inside_Rust’s_Meta.jpg|500px]]&lt;br /&gt;
&lt;br /&gt;
“Wait, Rust Has Macros?”&lt;br /&gt;
&lt;br /&gt;
If you’re new to Rust, the word macro probably evokes flashbacks to C’s preprocessor nightmares — #define spaghetti, double-evaluated expressions, and impossible-to-debug expansions. But Rust’s macros are nothing like that.&lt;br /&gt;
They’re not dumb text substitution engines.&lt;br /&gt;
 They’re syntactic transformers — fully aware of types, scopes, and syntax trees.&lt;br /&gt;
And with Macros 2.0, Rust is taking that power to the next level: structured, hygienic, and introspective meta-programming that changes how libraries, DSLs, and frameworks are built.&lt;br /&gt;
&lt;br /&gt;
The Real Goal Behind Macros 2.0&lt;br /&gt;
&lt;br /&gt;
The original macro_rules! system was powerful but limited. It was basically pattern matching on syntax — great for simple code generation, but terrible for introspection or advanced metaprogramming.&lt;br /&gt;
&lt;br /&gt;
It couldn’t:&lt;br /&gt;
* 		Look at types or names in context.&lt;br /&gt;
* 		Expand conditionally based on compiler state.&lt;br /&gt;
* 		Offer IDE tooling support (rust-analyzer used to cry over macros).&lt;br /&gt;
* 		Compose easily with procedural macros (#[derive], #[proc_macro_attribute], etc).&lt;br /&gt;
&lt;br /&gt;
Macros 2.0 — also called Declarative Macros 2.0 — is Rust’s quiet evolution of its meta-programming model, unifying the macro world under a cleaner, modular, and compiler-integrated system.&lt;br /&gt;
&lt;br /&gt;
Let’s unpack what that means.&lt;br /&gt;
&lt;br /&gt;
Macro Architecture — Then vs Now&lt;br /&gt;
&lt;br /&gt;
Let’s compare how Rust macros evolved:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
| Feature                                  | Macros 1.0 (`macro_rules!`) | Macros 2.0 |&lt;br /&gt;
| ---------------------------------------- | --------------------------- | ---------- |&lt;br /&gt;
| Defined at module scope                  | ✅ Yes                       | ✅ Yes      |&lt;br /&gt;
| Namespaced properly                      | ❌ No                        | ✅ Yes      |&lt;br /&gt;
| Hygiene (no accidental variable capture) | ✅ Partial                   | ✅ Full     |&lt;br /&gt;
| IDE support                              | ❌ Poor                      | ✅ Strong   |&lt;br /&gt;
| Unified token model with proc macros     | ❌ No                        | ✅ Yes      |&lt;br /&gt;
| Future compiler integration              | 🚫 Limited                  | 🧠 Deep    |&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So instead of macros living in a weird “shadow namespace,” Macros 2.0 gives them the same visibility, resolution, and hygiene as any other Rust item.&lt;br /&gt;
It’s no longer meta-magic. It’s meta-engineering.&lt;br /&gt;
&lt;br /&gt;
Let’s See One: Macros 1.0 vs 2.0 in Code&lt;br /&gt;
Here’s an old-school macro_rules! definition:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
macro_rules! make_pair {&lt;br /&gt;
    ($x:expr, $y:expr) =&amp;gt; {&lt;br /&gt;
        ($x, $y)&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
fn main() {&lt;br /&gt;
    let p = make_pair!(10, 20);&lt;br /&gt;
    println!(&amp;quot;{:?}&amp;quot;, p);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This works fine, but it’s stringly and pattern-based. The compiler doesn’t really “understand” the expansion — it just injects tokens.&lt;br /&gt;
&lt;br /&gt;
Now in Macros 2.0, defined inside a normal module scope:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pub macro make_pair($x:expr, $y:expr) {&lt;br /&gt;
    ($x, $y)&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* 		You can import it like a normal function:&lt;br /&gt;
* 		use crate::make_pair;&lt;br /&gt;
* 		It has real hygiene — no global pollution.&lt;br /&gt;
* 		It lives in the same symbol resolution system as everything else.&lt;br /&gt;
&lt;br /&gt;
Under the hood, this uses macro hygiene tables that track where each identifier originated — preventing accidental capture or collision.&lt;br /&gt;
Architecture of Rust’s Macro Expansion&lt;br /&gt;
&lt;br /&gt;
Here’s the internal pipeline simplified:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
┌──────────────────────────────┐&lt;br /&gt;
│     Source Code (Tokens)     │&lt;br /&gt;
└──────────────┬───────────────┘&lt;br /&gt;
               │&lt;br /&gt;
               ▼&lt;br /&gt;
┌──────────────────────────────┐&lt;br /&gt;
│ Macro Invocation Detected    │&lt;br /&gt;
│ (macro_rules!, derive, etc.) │&lt;br /&gt;
└──────────────┬───────────────┘&lt;br /&gt;
               │&lt;br /&gt;
               ▼&lt;br /&gt;
┌──────────────────────────────┐&lt;br /&gt;
│ Macro Resolver (Scoping +    │&lt;br /&gt;
│ Hygiene Resolution)          │&lt;br /&gt;
└──────────────┬───────────────┘&lt;br /&gt;
               │&lt;br /&gt;
               ▼&lt;br /&gt;
┌──────────────────────────────┐&lt;br /&gt;
│ Macro Expander               │&lt;br /&gt;
│ (TokenStream → TokenStream)  │&lt;br /&gt;
└──────────────┬───────────────┘&lt;br /&gt;
               │&lt;br /&gt;
               ▼&lt;br /&gt;
┌──────────────────────────────┐&lt;br /&gt;
│ Parsed into HIR (High-Level  │&lt;br /&gt;
│ Intermediate Representation) │&lt;br /&gt;
└──────────────┬───────────────┘&lt;br /&gt;
               │&lt;br /&gt;
               ▼&lt;br /&gt;
┌──────────────────────────────┐&lt;br /&gt;
│ Type Checking, MIR, LLVM     │&lt;br /&gt;
└──────────────────────────────┘&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Every macro — declarative, derive, or procedural — passes through the same TokenStream → TokenStream API now.&lt;br /&gt;
&lt;br /&gt;
This unified model is what enables IDE tooling, parallel compilation, and even incremental re-expansion when a macro changes.&lt;br /&gt;
&lt;br /&gt;
Inside a Procedural Macro&lt;br /&gt;
&lt;br /&gt;
Rust also supports procedural macros, which are like compiler plugins written in Rust.&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
use proc_macro::TokenStream;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
#[proc_macro_derive(HelloWorld)]&lt;br /&gt;
pub fn hello_world(_item: TokenStream) -&amp;gt; TokenStream {&lt;br /&gt;
    &amp;quot;impl HelloWorld { fn hello() { println!(\&amp;quot;Hello, world!\&amp;quot;); } }&amp;quot;&lt;br /&gt;
        .parse()&lt;br /&gt;
        .unwrap()&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you can use it as:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#[derive(HelloWorld)]&lt;br /&gt;
struct Foo;&lt;br /&gt;
&lt;br /&gt;
fn main() {&lt;br /&gt;
    Foo::hello();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The macro runs at compile time, generating the impl code before Rustc continues with type checking.&lt;br /&gt;
&lt;br /&gt;
Now here’s the twist: With Macros 2.0, these procedural macros are no longer special snowflakes. They share the same unified token API and namespace behavior as declarative macros.&lt;br /&gt;
&lt;br /&gt;
That’s how crates like serde_derive, async_trait, and thiserror seamlessly coexist.&lt;br /&gt;
&lt;br /&gt;
Code Flow Example: Macro Expansion in Action&lt;br /&gt;
&lt;br /&gt;
Let’s say we have this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#[derive(Debug)]&lt;br /&gt;
struct Point {&lt;br /&gt;
    x: i32,&lt;br /&gt;
    y: i32,&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here’s what actually happens:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
1. Parser sees #[derive(Debug)]&lt;br /&gt;
2. It looks up the registered macro “derive(Debug)” from the macro registry.&lt;br /&gt;
3. Rust loads the proc-macro crate that defines Debug.&lt;br /&gt;
4. The macro receives the struct definition as a TokenStream.&lt;br /&gt;
5. It outputs new tokens implementing fmt::Debug for Point.&lt;br /&gt;
6. The compiler injects those into the AST.&lt;br /&gt;
7. Compilation continues.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That’s not magic — it’s a deterministic compile-time transformation system.&lt;br /&gt;
&lt;br /&gt;
The Real Reason Macros 2.0 Exists&lt;br /&gt;
&lt;br /&gt;
Rust’s compiler team had three major goals:&lt;br /&gt;
* 		IDE-friendly meta-programming — the old macro system broke syntax trees, which made autocompletion impossible.&lt;br /&gt;
* 		Consistent hygiene — Rust wanted macros to be safe, not spooky.&lt;br /&gt;
* 		Future extensibility — allow macros that can introspect the compiler (e.g., see types, detect attributes, modify generics).&lt;br /&gt;
&lt;br /&gt;
Macros 2.0 unifies these under one model, so even tools like rust-analyzer and Clippy can work with macro-expanded code naturally.&lt;br /&gt;
Example: Building a DSL with Macros 2.0&lt;br /&gt;
&lt;br /&gt;
Let’s build a tiny embedded DSL:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pub macro sql($query:literal) {&lt;br /&gt;
    {&lt;br /&gt;
        println!(&amp;quot;Executing query: {}&amp;quot;, $query);&lt;br /&gt;
        // In real world: parse SQL, generate code, etc.&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
fn main() {&lt;br /&gt;
    sql!(&amp;quot;SELECT * FROM users WHERE age &amp;gt; 18&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now, imagine enhancing it with proc_macro to validate the query string at compile time:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
use proc_macro::TokenStream;&lt;br /&gt;
use syn::parse_macro_input;&lt;br /&gt;
use quote::quote;&lt;br /&gt;
&lt;br /&gt;
#[proc_macro]&lt;br /&gt;
pub fn sql(input: TokenStream) -&amp;gt; TokenStream {&lt;br /&gt;
    let query = parse_macro_input!(input as syn::LitStr);&lt;br /&gt;
    if !query.value().to_lowercase().contains(&amp;quot;select&amp;quot;) {&lt;br /&gt;
        panic!(&amp;quot;Only SELECT queries allowed!&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    let expanded = quote! {&lt;br /&gt;
        println!(&amp;quot;Executing safe SQL: {}&amp;quot;, #query);&lt;br /&gt;
    };&lt;br /&gt;
    expanded.into()&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now if you call sql!(&amp;quot;DELETE FROM users&amp;quot;), you’ll get a compile-time panic — the macro acts as a static guard.&lt;br /&gt;
&lt;br /&gt;
That’s the real beauty of Rust macros: they make domain-specific correctness possible at compile-time, not runtime.&lt;br /&gt;
&lt;br /&gt;
Architecture Insight: Macro Hygiene&lt;br /&gt;
&lt;br /&gt;
One of the biggest technical triumphs in Rust macros is hygiene.&lt;br /&gt;
Let’s say you write:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
macro_rules! make_var {&lt;br /&gt;
    () =&amp;gt; {&lt;br /&gt;
        let x = 10;&lt;br /&gt;
    };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
fn main() {&lt;br /&gt;
    let x = 5;&lt;br /&gt;
    make_var!();&lt;br /&gt;
    println!(&amp;quot;{}&amp;quot;, x);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You’d expect it to print 5, not 10, right? That’s because Rust tracks where each identifier came from.&lt;br /&gt;
&lt;br /&gt;
Internally, every token has an origin scope ID, so the compiler can tell that x inside the macro is not the same as x in main.&lt;br /&gt;
&lt;br /&gt;
That’s hygiene — and it’s why Rust macros are safe meta-programming instead of chaotic sorcery.&lt;br /&gt;
&lt;br /&gt;
How Macros 2.0 Changes the Ecosystem&lt;br /&gt;
&lt;br /&gt;
Here’s what this revolution means in practice:&lt;br /&gt;
* 		Frameworks like Axum, Serde, and Bevy use macros to auto-generate boilerplate.&lt;br /&gt;
* 		New compiler plugins are written entirely in Rust — not internal compiler hacks.&lt;br /&gt;
* 		Tools like rust-analyzer can expand macros on the fly with zero special cases.&lt;br /&gt;
* 		Future features like macro introspection (reading type info at compile time) become realistic.&lt;br /&gt;
&lt;br /&gt;
Rust has made meta-programming first-class, without sacrificing readability, hygiene, or compile-time safety.&lt;br /&gt;
&lt;br /&gt;
Final Thoughts&lt;br /&gt;
&lt;br /&gt;
If Rust’s borrow checker is what makes it safe, its macro system is what makes it expressive.&lt;br /&gt;
&lt;br /&gt;
Macros 2.0 is Rust’s quiet revolution — it brings metaprogramming out of the shadows, gives it structure, and turns it into something predictable, inspectable, and powerful.&lt;br /&gt;
&lt;br /&gt;
Every derive, every async fn, every DSL you’ve seen in Rust? They exist because the compiler now speaks meta-language fluently.&lt;br /&gt;
&lt;br /&gt;
Rust didn’t just reinvent macros. It made meta-programming sane.&lt;br /&gt;
* 		Macros 2.0 unifies declarative and procedural macros under one model.&lt;br /&gt;
* 		It fixes namespace, hygiene, and IDE visibility issues.&lt;br /&gt;
* 		It enables structured meta-programming and compile-time validation.&lt;br /&gt;
* 		It’s the foundation for frameworks like Serde, Bevy, and Axum.&lt;br /&gt;
* 		Rust’s metaprogramming future is clean, fast, and entirely written in Rust.&lt;/div&gt;</summary>
		<author><name>PC</name></author>
	</entry>
</feed>