# rust-petname
Generate human readable random names.
**🚨 UPGRADING FROM 2.x? There are a few breaking changes; please read the
[notes](#upgrading-from-2x).**
**🚨 UPGRADING FROM 1.x? There are several breaking changes; please read the
[notes](#upgrading-from-1x).**
[Petnames][petname-intro] are useful when you need to name a large number of
resources – like servers, services, perhaps bicycles for hire – and you want
those names to be easy to recall and communicate unambiguously. For example,
over a telephone compare saying "please restart remarkably-striking-cricket"
with "please restart s01O97i4": the former is easier to say and less likely to
be misunderstood. Avoiding sequential names adds confidence too: petnames have a
greater lexical distance between them, so errors in transcription can be more
readily detected.
This crate is both a command-line tool and a [Rust][rust-lang] library. Dustin
Kirkland's [petname][] project is the inspiration for this project. The word
lists and the basic command-line UX here are taken from there. Check it out!
Dustin maintains packages for [Python][petname-py], and [Golang][petname-go]
too.
Notable features:
- Choose from 3 built-in word lists, or provide your own.
- A `petnames!` macro to statically embed word lists at compile-time.
- Alliterative names, like _viable-vulture_, _proper-pony_, ...
- Build names with 1-255 components (adjectives, adverbs, nouns).
- Name components can be unseparated, or joined by any character or string.
- Generate 1..n names, or stream names continuously.
- **`no_std` support** (see [later section](#features--no_std-support)).
- Compile without built-in dictionaries to reduce library/binary size.
[rust-lang]: https://www.rust-lang.org/
[petname-intro]: https://blog.dustinkirkland.com/2015/01/introducing-petname-libraries-for.html
[petname]: https://github.com/dustinkirkland/petname
[petname-py]: https://pypi.org/project/petname/
[petname-go]: https://github.com/dustinkirkland/golang-petname
## Command-line utility
If you have [installed Cargo][install-cargo], you can install rust-petname with
`cargo install petname`. This puts a `petname` binary in `~/.cargo/bin`, which
the Cargo installation process will probably have added to your `PATH`.
The `petname` binary from rust-petname is _mostly_ drop-in compatible with the
original `petname`. It has more options and it's stricter when validating
arguments, but for most uses it should behave the same[^differences].
```shellsession
$ petname -h
Generate human readable random names
Usage: petname [OPTIONS]
Options:
-w, --words <WORDS> Number of words in name [default: 2]
-s, --separator <SEP> Separator between words [default: -]
--lists <LIST> Use the built-in word lists with small, medium, or large words [default: medium] [possible values: small, medium, large]
-c, --complexity <NUM> Alias for compatibility with upstream; prefer --lists instead
-d, --dir <DIR> Use custom word lists by specifying a directory containing `adjectives.txt`, `adverbs.txt`, and `nouns.txt`
--count <COUNT> Generate multiple names; or use --stream to generate continuously [default: 1]
--stream Stream names continuously
-l, --letters <LETTERS> Maximum number of letters in each word; 0 for unlimited [default: 0]
-a, --alliterate Generate names where each word begins with the same letter
-A, --alliterate-with <LETTER> Generate names where each word begins with the given letter
-u, --ubuntu Alias for compatibility with upstream; prefer --alliterate instead
--seed <SEED> Seed the RNG with this value (unsigned 64-bit integer in base-10)
-h, --help Print help (see more with '--help')
-V, --version Print version
Based on Dustin Kirkland's petname project <https://github.com/dustinkirkland/petname>.
$ petname
unified-platypus
$ petname -s _ -w 3
lovely_notable_rooster
```
### Performance
This implementation is considerably faster than the upstream `petname`:
```shellsession
$ time /usr/bin/petname
fit-lark
real 0m0.038s
user 0m0.032s
sys 0m0.008s
$ time target/release/petname
contiguous-seriema
real 0m0.004s
user 0m0.001s
sys 0m0.002s
```
These timings are irrelevant if you only need to name a single thing, but if you
need to generate 100s or 1000s of names then rust-petname is handy:
```shellsession
$ time { for i in $(seq 1000); do /usr/bin/petname; done; } > /dev/null
real 0m32.058s
user 0m29.360s
sys 0m5.163s
$ time { for i in $(seq 1000); do target/release/petname; done; } > /dev/null
real 0m2.293s
user 0m1.044s
sys 0m1.003s
```
To be fair, `/usr/bin/petname` is a shell script. The Go command-line version
(available from the golang-petname package on Ubuntu) is comparable to the Rust
version for speed, but has very limited options compared to its shell-script
ancestor and to rust-petname.
Lastly, rust-petname has a `--count` option that speeds up generation of names
considerably:
```shellsession
$ time target/release/petname --count=10000000 > /dev/null
real 0m0.785s
user 0m0.767s
sys 0m0.016s
```
That's ~408,000 (four hundred and eight thousand) times faster, for about 12.7
million petnames a second on this hardware. This is useful if you want to apply
an external filter to the names being generated:
```shellsession
Version 2.0 brought several breaking changes to both the API and the
command-line too. Below are the most important:
### Command-line
- The `--complexity <COMPLEXITY>` option has been replaced by `--lists <LISTS>`.
- For compatibility, `--complexity [0,1,2]` will still work, but its
availability is not shown in the `-h|--help` text.
- The default is now "medium" (equivalent to `--complexity 1`). Previously it
was "small" (`--complexity 0`).
- When using custom word lists with `--dir <DIR>`, nouns are now found in a file
named appropriately `DIR/nouns.txt`. Previously this was `names.txt` but this
was confusing; the term "names" is overloaded enough already.
- For compatibility, if `nouns.txt` is not found, an attempt will be made to
load nouns from `names.txt`.
- The option `--count 0` is no longer a synonym for `--stream`. Use `--stream`
instead. It's not an error to pass `--count 0`, but it will result in zero
names being generated.
- The `--non-repeating` flag is no longer recognised ([#101]).
### Library
- Feature flags have been renamed:
- `std_rng` is now `default-rng`,
- `default_dictionary` is now `default-words`.
- The `names` field on the `Petnames` struct has been renamed to `nouns`.
- `Petnames::new()` is now `Petnames::default()`.
- `Petnames::new(…)` now accepts word lists as strings.
- `Names` is no longer public. This served as the iterator struct returned by
`Petnames::iter(…)`, but this now hides the implementation details by
returning `impl Iterator<Item = String>` instead. This also means that
`Names::cardinality(&self)` is no longer available; use
`Petnames::cardinality(&self, words: u8)` instead.
- `Petnames::iter_non_repeating` has been removed ([#101]).
- `Petnames::generate`, `Petnames::generate_one`, and `Petnames::iter` have been
extracted into a `Generator` trait. This must be in scope in order to call
those methods ([#102]).
- The default word lists are now the "medium" lists.
[#101]: https://github.com/allenap/rust-petname/pull/101
[#102]: https://github.com/allenap/rust-petname/pull/102
## Developing & Contributing
To hack the source:
- [Install Cargo][install-cargo],
- Clone this repository,
- Build it: `cargo build`.
- Optionally, hide noise when using `git blame`: `git config blame.ignoreRevsFile .git-blame-ignore-revs`.
[install-cargo]: https://crates.io/install
### Running the tests
After installing the source (see above) run tests with: `cargo test`.
### Making a release
1. Bump version in [`Cargo.toml`](Cargo.toml).
1. Update the dependency on `petnames-macros` too.
1. Paste updated `-h` output into [`README.md`](README.md) (this file; see near
the top). On macOS the command `cargo run -- -h | pbcopy` is helpful.
**Note** that `--help` output is not the same as `-h` output: it's more
verbose and too much for an overview.
1. Build **and** test all crates in the workspace. Testing on its own does build
code, but a test build can hide warnings about dead code, so do both. To test
feature combinations, install [cargo-hack][] first, then:
- `cargo hack --workspace --feature-powerset build`
- `cargo hack --workspace --feature-powerset test`
1. Commit with message "Bump version to `$VERSION`."
1. Tag with "v`$VERSION`", e.g. `git tag v1.0.10`.
1. Push: `git push && git push --tags`.
1. Publish: `cargo publish`.
[cargo-hack]: https://crates.io/crates/cargo-hack
## License
This project is licensed under the Apache 2.0 License. See the
[LICENSE](LICENSE) file for details.