agentleFS
dawidpereiradawidpereira/rust-skills/skills/rust-macros/SKILL.md

rust-macros

Skill0 starsChanged 8 months agoMITView on GitHub

Rust macros — macro_rules!, proc macros, derive macros, attribute macros, fragment specifiers, repetition, hygiene, cargo expand, when to use macros vs generics. Use when writing or debugging declarative or procedural macros, choosing between macros and other abstractions, understanding expansion errors, or generating repetitive code.

5 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use rust-performance, rust-cli and 1 more.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • huialiSkill

    rust-performance

    Performance optimization expert covering profiling, benchmarking, memory allocation, SIMD, cache optimization, false sharing, lock contention, and NUMA-aware programming.

    Also in 4 projects that use this

  • tumfSkill

    rust-cli

    Design and implementation guidance for maintainable Rust CLIs with strong ergonomics, machine-friendly behavior, testable structure, and release automation. Use when creating or refactoring a Rust command-line tool, choosing crates like clap/anyhow/tracing/serde_json, improving command UX, adding JSON output, tightening test/release workflows, or making an existing CLI safer for agents and automation.

    Also in 3 projects that use this

  • huialiSkill

    rust-concurrency

    Concurrency and async programming expert. Handles Send, Sync, threads, async/await, tokio, channels, Mutex, RwLock, deadlock prevention, and race condition debugging.

    Also in 3 projects that use this

The file

We split this skill into the rules it gives an agent

2 rules. 0 are common, 1 is distinctive, and 1 is very specific to this project.

  • 0

    Common

    Most of the 4 edited versions we read keep these.

  • 1

    Distinctive

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Create syntax that Rust's type system cannot express

    line 133
  2. Very specific:

    Use $crate to reference items from the defining crate:

    line 145

“Common” is measured: kept by at least 6 in 10 of the 4 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Macros

Core Question

Is a macro the simplest way to eliminate this repetition, or would a function, generic, or trait do the job?

Macros generate code at compile time. They are powerful but harder to read, debug, and maintain than plain Rust. Reach for them only after ruling out simpler alternatives.


Error → Design Question

SymptomAsk Instead
"no rules expected the token"Does your fragment specifier match the input?
"unexpected end of macro"Are repetition delimiters balanced?
"macro expanded to expression"Does the call site expect a statement or expression?
"local ambiguity"Are your macro arms ordered most-specific-first?
Proc macro panicIs your TokenStream handling all input shapes?
"recursion limit reached"Is recursive expansion necessary, or can you restructure?

Quick Decisions

SituationReach ForWhy
Eliminating repeated struct/enum boilerplatemacro_rules! with repetitionGenerates variants without proc macro overhead
Code generation from attributesDerive proc macroRuns at compile time, integrates with #[derive]
Transforming function signaturesAttribute proc macroFull control over the annotated item
DSL or custom syntaxFunction-like proc macroArbitrary input parsing via syn
2–3 similar match armsJust duplicate the codeMacro not worth the complexity
Generating test casesmacro_rules! with test namesFast to write, easy to extend
Conditional compilationcfg attributes, not macrosBuilt-in, well-understood, no expansion
Debugging macro expansioncargo expandShows fully expanded code
Macro vs generic functionPrefer generic if types differ but logic is sameGenerics are type-checked, macros are not
Macro vs trait default implPrefer trait if behavior varies by typeTrait dispatch is idiomatic Rust
Exporting macros from library#[macro_export] for macro_rules!, re-export for proc macrosEnsures visibility across crate boundaries
Cross-crate proc macrosSeparate -derive or -macros crateProc macros must live in their own crate

Fragment Specifiers

SpecifierMatchesUse When
exprAny expressionValues, function calls, blocks
identIdentifierNames for types, functions, variables
tyTypeType parameters, annotations
patPatternMatch arms, let bindings
ttSingle token treeCatch-all, forwarding tokens
literalLiteral valueStrings, numbers, booleans
pathType pathstd::collections::HashMap
metaAttribute contentsderive(Debug), cfg(test)
itemTop-level itemFunctions, structs, impls
visVisibility qualifierpub, pub(crate), empty
stmtStatementLet bindings, expressions with ;
blockBrace-delimited block{ ... } bodies

Repetition Patterns

Three repetition operators with an optional separator:

macro_rules! make_list {
    // Zero or more
    ( $( $item:expr ),* ) => {
        vec![ $( $item ),* ]
    };
}

macro_rules! require_one {
    // One or more
    ( $( $item:expr ),+ ) => {
        vec![ $( $item ),+ ]
    };
}

macro_rules! optional_label {
    ( $( $label:ident : )? $value:expr ) => {
        println!("{}", $value);
    };
}

Nested repetition handles parallel lists:

macro_rules! impl_from {
    ( $target:ident : $( $source:ty => $variant:ident ),+ ) => {
        $(
            impl From<$source> for $target {
                fn from(val: $source) -> Self {
                    Self::$variant(val)
                }
            }
        )+
    };
}

The Macro vs Generic Decision

  1. Can a function do it? → Use a function.
  2. Can a generic do it? → Use a generic.
  3. Can a trait do it? → Use a trait.
  4. None of the above? → Then use a macro.

Macros are the right tool when you need to:

  • Generate new identifiers or types
  • Repeat code with varying structure (not just types)
  • Create syntax that Rust's type system cannot express
  • Implement a trait for a list of types

macro_rules! Hygiene

Identifiers inside macro_rules! are hygienic — they do not collide with names at the call site. However, this means a macro cannot reference local variables from the caller unless passed in as arguments.

Use $crate to reference items from the defining crate:

#[macro_export]
macro_rules! create_error {
    ( $msg:expr ) => {
        $crate::Error::new($msg)
    };
}

Without $crate, the macro breaks when used from another crate because Error resolves in the caller's namespace.


Usage Scenarios

Scenario 1: "I have 12 structs that all need the same trait impl with minor variations" → Write a macro_rules! with repetition that takes the struct name and the varying parts as parameters. See references/declarative.md for trait impl patterns.

Scenario 2: "I want to generate tests for multiple input/output pairs" → Use macro_rules! to generate #[test] functions with unique names from a list of cases. See references/declarative.md for test generation.

Scenario 3: "I need a #[derive(MyTrait)] that generates methods based on struct fields" → Create a proc macro crate with syn and quote. Parse DeriveInput, iterate fields, emit impl block. See references/procedural.md for derive macro setup.


Reference Files

FileRead When
references/declarative.mdWriting macro_rules!, fragment specifiers, repetition patterns, common recipes, debugging with cargo expand
references/procedural.mdDerive macros, attribute macros, function-like macros, syn/quote, proc macro testing

Cross-References

WhenCheck
Generics as alternative to macrosrust-types → Quick Decisions
Test generation macrosrust-tests → Quick Decisions
cargo expand and lint setuprust-quality → Quick Decisions
Macro naming and documentationrust-api → Quick Decisions

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.