huiali/rust-skills/rust-macro

Claude Code and agent skill by huiali/rust-skills

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

Macro and procedural metaprogramming expert covering macro_rules!, derive macros, proc-macros, compile-time computation, and code generation patterns.

Install

npx vskill@latest install huiali/rust-skills/rust-macro

SKILL.md

Macros vs Generics

DimensionMacrosGenerics
FlexibilityCode transformationType abstraction
Compile costIncremental-friendlyMonomorphization overhead
Error messagesCan be crypticClear
DebuggingDebug expanded codeDirect debugging
Use caseReduce boilerplateGeneric algorithms

Solution Patterns

Pattern 1: Declarative Macro (macro_rules!)
rust
// Basic structure
macro_rules! my_vec {
// Empty case
() => {
Vec::new()
};
// List of elements
($($elem:expr),* $(,)?) => {{
let mut v = Vec::new();
$(
v.push($elem);
)*
v
}};
// Repeated element
($elem:expr; $n:expr) => {
vec![$elem; $n]
};
}
// Usage
let v1 = my_vec![];
let v2 = my_vec![1, 2, 3];
let v3 = my_vec![0; 10];
Pattern 2: Derive Macro
rust
// In a separate proc-macro crate
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};
#[proc_macro_derive(Builder)]
pub fn derive_builder(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = &input.ident;
let builder_name = format!("{}Builder", name);
let builder_ident = syn::Ident::new(&builder_name, name.span());
let fields = match &input.data {
syn::Data::Struct(data) => &data.fields,
_ => panic!("Builder only works on structs"),
};
let field_names: Vec<_> = fields.iter()
.filter_map(|f| f.ident.as_ref())
.collect();
let field_types: Vec<_> = fields.iter()
.map(|f| &f.ty)
.collect();
let expanded = quote! {
pub struct #builder_ident {
#(#field_names: Option<#field_types>),*
}
impl #builder_ident {
pub fn new() -> Self {
Self {
#(#field_names: None),*
}
}
#(
pub fn #field_names(mut self, value: #field_types) -> Self {
self.#field_names = Some(value);
self
}
)*
pub fn build(self) -> Result<#name, String> {
Ok(#name {
#(
#field_names: self.#field_names
.ok_or_else(|| format!("Field {} not set", stringify!(#field_names)))?
),*
})
}
}
impl #name {
pub fn builder() -> #builder_ident {
#builder_ident::new()
}
}
};
expanded.into()
}
Pattern 3: Function-like Proc Macro
rust
#[proc_macro]
pub fn sql(input: TokenStream) -> TokenStream {
let sql_string = input.to_string();
// Parse and validate SQL at compile time
validate_sql(&sql_string);
// Generate code
quote! {
QueryBuilder::raw(#sql_string)
}.into()
}
// Usage:
let query = sql!("SELECT * FROM users WHERE id = ?");
Pattern 4: Attribute Macro
rust
#[proc_macro_attribute]
pub fn cached(_attr: TokenStream, item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as ItemFn);
let fn_name = &input.sig.ident;
let fn_body = &input.block;
let expanded = quote! {
fn #fn_name() -> Result {
use std::sync::OnceLock;
static CACHE: OnceLock<Result> = OnceLock::new();
CACHE.get_or_init(|| {
#fn_body
}).clone()
}
};
expanded.into()
}
// Usage:
#[cached]
fn expensive_computation() -> String {
// ...
}

Repetition Patterns

SyntaxMeaning
$()Match zero or more
$($x),*Comma-separated
$($x),+At least one
$x:tyType matcher
$x:exprExpression matcher
$x:patPattern matcher
$x:identIdentifier matcher
$x:pathPath matcher
$x:ttToken tree matcher
rust
// Example: multiple matchers
macro_rules! create_struct {
($name:ident { $($field:ident: $type:ty),* }) => {
struct $name {
$($field: $type),*
}
};
}
create_struct!(User {
id: u64,
name: String,
email: String
});

Workflow

Step 1: Consider Alternatives
Need to reduce duplication?
→ Can generics solve it? Prefer generics
→ Need syntax transformation? Use macros
→ Need to inspect types? Derive macro
→ Need attribute? Attribute macro
Step 2: Choose Macro Type
Declarative (macro_rules!)?
✅ Simple pattern matching
✅ Quick to write
❌ Limited power
Procedural (proc-macro)?
✅ Full AST access
✅ Complex transformations
❌ Separate crate needed
❌ Longer compile times
Step 3: Debug Expansion
bash
# Expand macros
cargo expand
# Expand specific function
cargo expand my_module::my_function
# Expand tests
cargo expand --test test_name
Step 4: Test Thoroughly
rust
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_macro_expansion() {
// Test generated code
let result = my_macro!(input);
assert_eq!(result, expected);
}
}

Common Crates

CratePurpose
synParse Rust syntax
quoteGenerate Rust code
proc-macro2Token manipulation
derive-moreCommon derive macros
darlingParse macro attributes

Best Practices

PracticeReason
Try generics firstSafer, easier to debug
Keep macros simpleComplex macros hard to maintain
Document macrosUsers need to understand expansion
Test expansionEnsure correctness
Use cargo expandVisualize macro output

Review Checklist

When reviewing macro code:

  • [ ] Could this be solved with generics instead?
  • [ ] Macro expansion documented with examples
  • [ ] Error messages are helpful
  • [ ] Edge cases tested
  • [ ] Hygiene respected (no accidental captures)
  • [ ] Used cargo expand to verify output
  • [ ] Compile-time overhead acceptable
  • [ ] No unnecessary proc-macro dependency

Verification Commands

bash
# Expand macros
cargo expand
# Expand specific module
cargo expand path::to::module
# Check proc-macro crate
cargo check -p my-proc-macro
# Test expansion
cargo test --all-features

Common Pitfalls

1. Hygiene Violations

Symptom: Unexpected variable captures

rust
// ❌ Bad: name clash risk
macro_rules! bad_macro {
($x:expr) => {{
let result = $x; // 'result' might clash
result
}};
}
// ✅ Good: use unique names
macro_rules! good_macro {
($x:expr) => {{
let __macro_result = $x;
__macro_result
}};
}
2. Complex Error Messages

Symptom: Users don't understand macro errors

rust
// ✅ Good: helpful error messages
macro_rules! require_trait {
($t:ty) => {
const _: fn() = || {
fn assert_impl<T: MyTrait>() {}
assert_impl::<$t>();
};
};
}
3. Proc Macro Compile Time

Symptom: Slow incremental builds

rust
// ❌ Avoid: heavy proc macros for simple tasks
#[derive(HeavyProcMacro)]
struct Simple {
field: String,
}
// ✅ Better: manual impl or simpler derive
impl Simple {
// Manual implementation
}

Related Skills

  • rust-coding - Naming macro conventions
  • rust-performance - Macro compile-time cost
  • rust-type-driven - When generics suffice
  • rust-error - Error handling in macros
  • rust-testing - Testing macro expansion

Localized Reference

  • Chinese version: SKILL_ZH.md - 完整中文版本,包含所有内容

Security

  • Security scanPassed, 100 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
20
Repository forks
4
7-day trend score
15

Stars and forks are for the whole GitHub repository, not this skill alone. Refreshed 21 Mar 2026, 7 months ago.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/huiali/rust-skills/rust-macro/badge)](https://verified-skill.com/skills/huiali/rust-skills/rust-macro)

Something wrong with this skill or its page? Tell us.