Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsBlogPro
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges
  • Chrome Extension
  • Skill Manager

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Rust Macros

ASecurity

Write a macro only when a function, a trait, or a generic cannot do the job — then by-example before proc-macro, with hygiene, a `_private` helper module, and spanned compile errors instead of panics. Use when writing or reviewing macro_rules! or a proc macro, when a derive or attribute macro is being added, when macro hygiene or `$crate` comes up, or when the user asks whether something should be a macro.

2 stars
0 votes
0 copies
2 views
Added 9/19/2026
developmentrustgobashapi

Works with

cliapi

Security Analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned 9/19/2026

$npx -y skills add rewrite-rs/skills --skill rust-macros --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Rust Macros?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Rust Macros
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/rewrite-rs-rust-macros/badge)](https://www.skillsdirectory.com/skills/rewrite-rs-rust-macros)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
Files
SKILL.md
---
name: rust-macros
description: Write a macro only when a function, a trait, or a generic cannot do the job — then by-example before proc-macro, with hygiene, a `_private` helper module, and spanned compile errors instead of panics. Use when writing or reviewing macro_rules! or a proc macro, when a derive or attribute macro is being added, when macro hygiene or `$crate` comes up, or when the user asks whether something should be a macro.
---

# Rust Macros

The first question a macro must answer is why it is not a function, a trait,
or a generic — and usually the answer is that it is not.

## A macro is a last resort

Most macros exist to avoid typing, and the cost they charge is paid by every
reader afterwards: no jump-to-definition worth the name, error messages
pointing at expansions, no type checking until the expansion happens. The
genuine answers are three — a variadic interface, generating an impl per
type from a list, and a DSL whose syntax is not Rust. Name the case; if it
is not one of the three, reach for the non-macro and say which.

## By-example before procedural

`macro_rules!` is in the same crate, needs no dependency, and can be read. A
proc macro needs its own crate, a `syn`/`quote` dependency pair, and compiles
before the crate that uses it. Reach for it when the input has to be parsed
as Rust syntax — what derives and attribute macros are — and not before.

## Hygiene, and `$crate`

A macro expands at the call site, where the names it mentions may mean
something else. `$crate` resolves to the defining crate no matter where the
expansion lands, and a macro that names any item from its own crate without
it works only until someone invokes it from a module that shadows the path.
Local variables a `macro_rules!` introduces are hygienic and cannot collide;
paths and types are not.

## Fragment specifiers say what you accept

`expr`, `ty`, `ident`, `pat`, `literal`, `tt` — pick the narrowest that fits,
because the specifier is the error message. A macro taking `tt` accepts
anything and reports the failure somewhere inside the expansion, where no
one will look.

```rust
macro_rules! min_of {
    ($a:expr, $b:expr) => { if $a < $b { $a } else { $b } };
}
pub fn pair_min(a: i32, b: i32) -> i32 {
    min_of!(a, b)
}
```

## A macro does not lie about the signature

If the macro generates a function, the generated signature is the one the
caller sees in an error, so it carries real types and real names. Never
generate an item whose name the user did not write and cannot search for —
an implied item is a symbol in errors from a place the reader cannot find.

## The `_private` helper module

Anything the expansion must reference goes in a `#[doc(hidden)] pub mod
_private`, referenced through `$crate::_private::…`, so it is reachable by
the expansion and marked as no part of the public API. Without it, the
helpers become public surface you cannot change.

```rust,ignore
#[doc(hidden)]
pub mod _private {
    use std::sync::atomic::{AtomicUsize, Ordering};
    pub fn next_id() -> usize {
        static NEXT: AtomicUsize = AtomicUsize::new(0);
        NEXT.fetch_add(1, Ordering::Relaxed) + 1
    }
}
macro_rules! next_id {
    () => {
        $crate::_private::next_id()
    };
}
pub fn assign() -> usize {
    next_id!()
}
```

## Proc-macro crates: keep the implementation separate

The proc-macro crate can export nothing but macros, so the logic lives in a
plain sibling crate that the proc-macro crate calls; the sibling is
unit-testable without a compiler harness, which is the actual reason.

## Errors are spanned, never panics

A proc macro that panics reports "proc macro panicked" with no location. A
`syn::Error` built with `new_spanned` and turned into a compile error by
`to_compile_error` points the compiler at the user's own code — the
difference between a macro people use and one they work around.

```rust,ignore
fn expand(input: &syn::DeriveInput) -> proc_macro2::TokenStream {
    if input.generics.type_params().count() > 1 {
        return syn::Error::new_spanned(&input.generics, "too many generics")
            .to_compile_error();
    }
    // build the derived impl with quote
}
```

## Deferrals

Whether the generated API should exist at all is `/rust-api-design`. What a
generated error type looks like is `/rust-errors`. Derives that already exist
and should be used instead of a hand-written impl are `/idiomatic-rust`.
Serde attribute behaviour is `/rust-serde`.

## Verification

```bash
cargo expand --lib          # read the expansion; if it is not installed, propose it, do not require it
cargo test                  # including a trybuild suite if the crate has one
cargo clippy --all-targets  # at the level the repo configures
```

A macro crate without a `trybuild` (or equivalent) test of its failure cases
has never checked the thing users complain about, which is the error message.

Attribution

rewrite-rsrewrite-rs
View sourceSee grades on GitHubMore from rewrite-rs →
SSkills DirectorySkills Directory

Your tool, in front of Claude Code builders.

3 founder slots · $299/mo · GSC-verified traffic · sponsors can never buy grades.

See placements

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Your tool, in front of Claude Code builders.

3 founder slots · $299/mo · GSC-verified traffic · sponsors can never buy grades.

See placements

Related Skills

Clean Code

Pragmatic coding standards - concise, direct, no over-engineering, no unnecessary comments

304955 votes

Browser Extension Developer

Use this skill when developing or maintaining browser extension code in the `browser/` directory, including Chrome/Firefox/Edge compatibility, content scripts, background scripts, or i18n updates.

285172 votes

Seo Optimizer

SEO optimization with keyword analysis, readability assessment, technical validation, content quality. Use for search rankings, blog posts, content audits, or encountering keyword density, readability scores, meta tags, schema markup errors.

2222 votes

Google Official Seo Guide

Official Google SEO guide covering search optimization, best practices, Search Console, crawling, indexing, and improving website search visibility based on official Google documentation

1862 votes

Tanstack Start

Build a full-stack TanStack Start app on Cloudflare Workers from scratch — SSR, file-based routing, server functions, D1+Drizzle, better-auth, Tailwind v4+shadcn/ui. Use whenever the user mentions TanStack Start, asks to scaffold a full-stack Cloudflare app with SSR, wants an SSR dashboard, or asks for a React 19 + Cloudflare Workers app with file-based routing and server functions — even if they don't name TanStack Start specifically. No template repo — Claude generates every file fresh per ...

10311 votes
View all in development →