Declarative and Procedural Macros in Depth

Function-Like Macro Architecture

A function-like procedural macro—declared with #[proc_macro]—is invoked with ! syntax (sql!("SELECT ..."), html! { <div /> }) just like a macro_rules! macro, but executes arbitrary Rust code at compile time over its input TokenStream.

When to Choose #[proc_macro] Over macro_rules!

Requirement macro_rules! (Declarative) #[proc_macro] (Function-Like Proc Macro)
Simple pattern substitution & repetition Ideal (lives in same crate, fast compile time) Overkill (requires separate proc-macro crate)
Constructing new identifiers (concat_idents) or case conversion (snake_case $\rightarrow$ PascalCase) Limited Full string manipulation on Ident::to_string()
Compile-time validation of string literals (SQL queries, regexes, HTML, format strings) Cannot inspect characters inside "..." literal Can parse and validate string contents at compile time!
Stateful compilation / deduplication / complex algorithms Difficult (requires recursive TT munching) Standard Rust Vec, HashMap, loops, and structs
Compile-Time DSL Verification with `#[proc_macro]`:

  let route = verified_route!("/users/:id/posts");
                    |
                    v  [ Runs inside `rustc` at compile time ]
              1. Extracts string literal `"/users/:id/posts"`
              2. Validates starts with `/` and has valid parameter names
              3. Emits pre-parsed static `RouteSpec` struct literal (or compile_error!)

Architecture of a Compile-Time Validating Function-Like Macro

Below is the architecture of a function-like procedural macro verified_route!("/users/:id") that parses and validates route segments at compile time and expands to a zero-cost RouteSpec literal:

// Inside a `proc-macro = true` crate:
/*
use proc_macro::TokenStream;
use quote::quote;
use syn::{LitStr, parse_macro_input};

#[proc_macro]
pub fn verified_route(input: TokenStream) -> TokenStream {
    let lit = parse_macro_input!(input as LitStr);
    let path = lit.value();

    if !path.starts_with('/') {
        return syn::Error::new(lit.span(), "route path must start with '/'")
            .to_compile_error()
            .into();
    }

    let params: Vec<String> = path
        .split('/')
        .filter_map(|seg| seg.strip_prefix(':'))
        .map(str::to_string)
        .collect();

    quote! {
        RouteSpec {
            pattern: #lit,
            param_names: &[ #( #params ),* ],
        }
    }
    .into()
}
*/

// Runnable demonstration of the compile-time validation logic and generated struct:
#[derive(Debug)]
struct RouteSpec {
    pattern: &'static str,
    param_names: &'static [&'static str],
}

fn main() {
    // Generated at compile time by `verified_route!("/orgs/:org_id/users/:user_id")`:
    const USERS_ROUTE: RouteSpec = RouteSpec {
        pattern: "/orgs/:org_id/users/:user_id",
        param_names: &["org_id", "user_id"],
    };

    println!("compiled route: {:?}", USERS_ROUTE);
}
compiled route: RouteSpec { pattern: "/orgs/:org_id/users/:user_id", param_names: ["org_id", "user_id"] }