rust-petname
Generate human-readable random names like remarkably-striking-cricket, as a Rust library or CLI, with built-in English, Turkish, and Luxembourgish word lists.
Repository Health
Technical Analysis
rust-petname is a Rust reimplementation of Dustin Kirkland’s petname project: it builds memorable, easy-to-say names for resources you’d otherwise have to label with sequential IDs or UUIDs — servers, containers, test fixtures, hire bicycles, anything that benefits from a name a human can recall and repeat over a phone call without transcription errors.
The crate is both a library and a command-line tool. As a library it centers on a small, object-safe Generator trait implemented by Petnames (word-list-backed generation) and Alliterations (names where every word shares an initial letter, like proper-pony), both produced via a Namer that exposes either a buffer-reusing generate_into call or a standard Rust Iterator. It is no_std compatible, so it can run in constrained environments like WebAssembly given an external source of randomness.
Word lists ship for English, Turkish, and Luxembourgish, each modeled as its own generator rather than forced through a shared abstraction — Turkish adds emphatic reduplication of adjectives, Luxembourgish adds grammatical gender agreement and the Eifeler Regel sandhi rule at word joins. Custom word lists can be embedded at compile time via the petnames!/english! proc macros, or supplied at runtime.
The petname binary is close to drop-in compatible with the original shell-script petname tool, but runs orders of magnitude faster, with a --count flag capable of streaming millions of names per second and shell-completion generation for bash, zsh, fish, elvish, and PowerShell.
What You Get
- A
Generatortrait implemented byPetnames(word-list-backed) andAlliterations(same-initial-letter names), usable as trait objects - A
Namerwith both an allocation-freegenerate_into(&mut String, ...)call and a standardIteratorfor streaming names - Three built-in word-list sizes (small/medium/large) for English, plus dedicated Turkish and Luxembourgish generators with real grammar rules (emphatic reduplication, gender agreement, sandhi)
- The
petnames!/english!proc macros to embed your own word lists at compile time, or load lists at runtime instead - A
petnameCLI binary — largely drop-in compatible with the original shell-script petname tool, but with a--count/--streammode that generates millions of names per second, plus shell-completion generation no_stdsupport (withextern crate alloc) so the generator can run in constrained environments like Wasm
Common Use Cases
- Naming ephemeral cloud resources — servers, containers, VMs — with something easier to say aloud than a hex ID
- Generating friendly default names for test fixtures, demo data, or sandboxed accounts
- Building CLI tools or scripts that need bulk unique-ish names fast (millions per second via
--count) - Producing alliterative or themed names (e.g. all starting with the same letter) for playful product features
- Adding non-English (Turkish, Luxembourgish) name generation to a Rust project without hand-rolling grammar rules
Under The Hood
Architecture
The library centers on one object-safe trait, Generator, with a single required method generate_into(&self, buf, rng, words, separator). Petnames<'a> (in src/lang/english.rs, re-exported at the crate root) holds three Cow<[&str]> word lists — adjectives, adverbs, nouns — and a private Lists iterator (src/lib.rs) sequences which list to draw from for a requested word count (adverbs first, then one adjective, then a noun). Alliterations<'a> wraps a BTreeMap<char, Petnames<'a>> built by grouping every word by first letter via From<Petnames>, so a generated name naturally alliterates without extra runtime filtering. Both types are driven through a shared Namer<'a, G> config struct (word count + separator + generator reference) that exposes either generate_into for buffer reuse or iter for a standard Rust Iterator built on core::iter::from_fn. This keeps the hot path allocation-light: one String per name via iter, or zero extra allocations if the caller reuses a buffer directly.
Tech Stack
A no_std crate (extern crate alloc) depending on rand 0.10 (default-features off, thread_rng opt-in via a default-rng feature) for randomness, with the CLI binary layered on clap 4 (cargo, derive features) and clap_complete for shell completions — both gated behind a clap feature so the library itself pulls in neither. A companion petname-macros proc-macro crate (workspace member) implements the english!/turkish!/luxembourgish!/petnames! macros that read word-list files at compile time and embed them as static arrays; syn/quote-style proc-macro parsing lives in its input.rs, paths.rs, and text.rs. The release profile is tuned for small binaries (lto = true, opt-level = "z", strip = true), and docs.rs metadata builds with --all-features plus --cfg docsrs so feature-gated items get labeled in generated docs.
Code Quality
Extensive test coverage across tests/petname.rs, tests/petnames.rs, tests/alliterations.rs, tests/macros.rs, and tests/integration.rs, plus a large body of runnable doctests embedded directly in src/lib.rs’s rustdoc comments — CI runs both cargo hack --workspace --feature-powerset build and test, meaning every combination of feature flags is exercised, not just the defaults. CI additionally enforces cargo fmt --check, cargo clippy -- -D warnings (warnings treated as errors), and a cargo doc build that fails on warnings. unwrap()/expect() usage is confined to test helper code, not library logic. The crate carries an AGENTS.md file documenting its own architecture and conventions for future contributors, including an explicit rationale for why each language generator is a hand-duplicated type rather than a shared abstraction.
What Makes It Unique
Most random-name generators stop at English word-list concatenation; this one treats non-English languages as first-class grammar problems rather than word-list swaps. The Turkish generator models emphatic reduplication of adjectives (a real Turkish morphological feature), and the Luxembourgish generator tracks grammatical gender per noun, agrees adjective endings across three forms, and applies a phonological sandhi rule (the Eifeler Regel, dropping a final -n before most consonants) at the join between words — verified by a unit test that lints the built-in word-list data itself, so a bad curation entry fails CI rather than shipping silently. Combined with the deliberate choice to keep the library no_std and allocate minimally via generate_into, it’s built for embedding in latency- or size-sensitive contexts, not just as a developer-convenience CLI.