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
- po4yka/rust-skillstheir own version, first seen Nov 2, 2026
- full-stack-skills/rust-skillstheir own version, first seen Oct 15, 2026
- Lu1sDV/skillsmdtheir own version, first seen Oct 13, 2026
- botirkhaltaev/botir-skillstheir own version, first seen Jul 24, 2026
- Microbiosis/rust-claude-skillstheir own version, first seen May 28, 2026
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.
huialiSkillrust-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
tumfSkillrust-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
huialiSkillrust-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
Other versions5 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 5
- full-stack-skills/rust-skills★ 8same name
- po4yka/rust-skills★ 5same name
- botirkhaltaev/botir-skills★ 4same name
- Lu1sDV/skillsmd★ 2same name
- Microbiosis/rust-claude-skills★ 1same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository16 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- rust-apiSkill
- rust-architectureSkill
- rust-asyncSkill
- rust-ci-deploySkill
- rust-databaseSkill
- rust-dddSkill
- rust-errorsSkill
- rust-ownershipSkill
- rust-perfSkill
- rust-qualitySkill
- rust-serdeSkill
- rust-testsSkill
- rust-tracingSkill
- rust-typesSkill
- rust-unsafeSkill
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
- Distinctive: line 133
Create syntax that Rust's type system cannot express
- Very specific: line 145
Use $crate to reference items from the defining crate:
“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.
Files
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
| Symptom | Ask 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 panic | Is your TokenStream handling all input shapes? |
| "recursion limit reached" | Is recursive expansion necessary, or can you restructure? |
Quick Decisions
| Situation | Reach For | Why |
| Eliminating repeated struct/enum boilerplate | macro_rules! with repetition | Generates variants without proc macro overhead |
| Code generation from attributes | Derive proc macro | Runs at compile time, integrates with #[derive] |
| Transforming function signatures | Attribute proc macro | Full control over the annotated item |
| DSL or custom syntax | Function-like proc macro | Arbitrary input parsing via syn |
| 2–3 similar match arms | Just duplicate the code | Macro not worth the complexity |
| Generating test cases | macro_rules! with test names | Fast to write, easy to extend |
| Conditional compilation | cfg attributes, not macros | Built-in, well-understood, no expansion |
| Debugging macro expansion | cargo expand | Shows fully expanded code |
| Macro vs generic function | Prefer generic if types differ but logic is same | Generics are type-checked, macros are not |
| Macro vs trait default impl | Prefer trait if behavior varies by type | Trait dispatch is idiomatic Rust |
| Exporting macros from library | #[macro_export] for macro_rules!, re-export for proc macros | Ensures visibility across crate boundaries |
| Cross-crate proc macros | Separate -derive or -macros crate | Proc macros must live in their own crate |
Fragment Specifiers
| Specifier | Matches | Use When |
expr | Any expression | Values, function calls, blocks |
ident | Identifier | Names for types, functions, variables |
ty | Type | Type parameters, annotations |
pat | Pattern | Match arms, let bindings |
tt | Single token tree | Catch-all, forwarding tokens |
literal | Literal value | Strings, numbers, booleans |
path | Type path | std::collections::HashMap |
meta | Attribute contents | derive(Debug), cfg(test) |
item | Top-level item | Functions, structs, impls |
vis | Visibility qualifier | pub, pub(crate), empty |
stmt | Statement | Let bindings, expressions with ; |
block | Brace-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
- Can a function do it? → Use a function.
- Can a generic do it? → Use a generic.
- Can a trait do it? → Use a trait.
- 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
| File | Read When |
| references/declarative.md | Writing macro_rules!, fragment specifiers, repetition patterns, common recipes, debugging with cargo expand |
| references/procedural.md | Derive macros, attribute macros, function-like macros, syn/quote, proc macro testing |
Cross-References
| When | Check |
| Generics as alternative to macros | rust-types → Quick Decisions |
| Test generation macros | rust-tests → Quick Decisions |
| cargo expand and lint setup | rust-quality → Quick Decisions |
| Macro naming and documentation | rust-api → Quick Decisions |
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
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.

