seq-macro
A seq! macro that repeats a fragment of Rust source code, substituting a sequential numeric, byte, or char counter into each repetition at compile time.
Repository Health
Technical Analysis
seq-macro is a small, focused procedural macro crate from David Tolnay (the author of serde, syn, and thiserror) that brings for-loop-style repetition to Rust source code generation. Its single seq! macro takes a variable name, a numeric/byte/char range, and a block of code, then expands that block once per value in the range, substituting the counter wherever it appears — either standalone or concatenated onto an identifier prefix with ~N to build sequential names like Variant0, Variant1, and so on.
This solves a specific gap in Rust’s macro system: ordinary macro_rules! and for loops can’t generate a sequence of differently-named items (structs, functions, enum variants, tuple-field accesses) because Rust has no native way to loop at the token level with an incrementing literal. seq-macro fills that gap without pulling in a general-purpose templating engine or build-script code generation step — it works entirely through the standard proc_macro API and expands inline wherever seq!{} is invoked.
The crate is deliberately narrow in scope, has no runtime dependencies, and supports #![no_std] and no_std::no_alloc environments, making it suitable for embedded and systems code as well as ordinary application crates. It has shipped essentially unchanged in behavior since 2018, with periodic maintenance releases keeping pace with newer Rust editions and lint suites.
What You Get
- The
seq!(N in START..END { ... })macro for repeating an entire code block across a numeric range - Selective repetition via
#( ... )*markers so only part of the body repeats while the rest stays fixed - Identifier concatenation with
Prefix~Nsyntax to generate sequential names likeVariant0,Pin00A, orf1 - Support for integer, byte (
b'a'..=b'z'), and character ('a'..='z') ranges, inclusive or exclusive - Preservation of binary, octal, hex, and zero-padded literal formatting in generated output
no_stdandno_std::no_alloccompatibility for embedded and systems use
Common Use Cases
- Generating repetitive struct/enum definitions such as pin types, opcode tables, or register bindings that differ only by a numeric suffix
- Unrolling fixed-size tuple or array field access (
tuple.0,tuple.1, …) that can’t be reached with a runtime loop - Building sequential trait implementations or function stubs across a fixed range for benchmarking or testing harnesses
- Reducing hand-written boilerplate in hardware-abstraction-layer (HAL) crates that enumerate many near-identical peripherals
Under The Hood
Architecture
The crate is a single proc-macro = true library exposing one entry point, seq() in src/lib.rs, which delegates parsing to src/parse.rs and then performs substitution in two passes: expand_repetitions walks the token tree looking for #( ... )* markers and, if found, repeats only the marked sub-stream per value in the range; if no marker is found, repeat falls back to repeating the entire body. Token substitution itself (substitute_value) recurses into nested groups, replacing bare occurrences of the loop variable with a literal and Prefix~N pairs with a freshly concatenated identifier. Errors are represented as a SyntaxError struct carrying a message and a Span, converted into a compile_error!{} token stream so failures surface at the correct source location rather than as an opaque panic.
Tech Stack
The crate targets Rust edition 2021 with an MSRV of 1.68, built directly on the standard library’s proc_macro API (Delimiter, Group, Ident, Literal, Span, TokenStream, TokenTree) with zero runtime dependencies. Dev-dependencies are limited to rustversion and trybuild for compile-fail UI testing. Cargo.toml declares no-std and no-std::no-alloc categories, and docs.rs metadata configures link-to-definition and macro-expansion rustdoc output.
Code Quality
Testing combines ordinary #[test] functions in tests/test.rs covering expansion correctness (function generation, stringification, underscore handling, nested groups) with trybuild-driven UI tests under tests/ui/ that assert specific compile errors and their spans for malformed input. The CI workflow runs the full matrix across nightly, beta, stable, and the pinned MSRV, plus a dedicated Miri job with strict-provenance flags, a cargo clippy --tests -Dclippy::all -Dclippy::pedantic job, and a rustdoc build with warnings denied — an unusually rigorous quality bar for a crate of this size, consistent with the author’s other widely-used proc-macro crates.
What Makes It Unique
Rather than offering a general templating or code-generation DSL, seq-macro solves exactly one problem — sequential, counter-driven repetition — through a minimal, dependency-free token-level implementation. Its identifier-concatenation syntax (Prefix~N) and support for byte/char ranges with format-preserving radix (binary/octal/hex/zero-padded) are handled directly in the substitution logic rather than delegated to a heavier macro framework, keeping compile times low and behavior predictable for embedded and systems code that can’t tolerate macro-expansion overhead.