anarchist_readable_name_generator_lib/
lib.rs

1//! This library uses the authors from Anarchist Library to generate a random name
2//!
3//! The intention here is to have a random name for situations you need to spin up some cloud compute resources and don't have a name in mind. Typically, for throwaway purposes.
4//!
5//! # Examples
6//!
7//! It's possible to simply generate a random name
8//!
9//! ```
10//! use anarchist_readable_name_generator_lib::readable_name;
11//!
12//! assert!(readable_name().len() > 0)
13//! ```
14//!
15//! You can also pass a seed or change the separator to give you predictability or minor customization.
16//!
17//! ```
18//! use anarchist_readable_name_generator_lib::readable_name_custom;
19//! use rand::prelude::*;
20//! use rand_chacha::ChaChaRng;
21//!
22//! let rng = ChaChaRng::seed_from_u64(2);
23//! assert_eq!(
24//!    readable_name_custom("+", rng),
25//!    "romantic+kamalmaz"
26//! );
27//! ```
28
29#![warn(clippy::nursery)]
30#![deny(
31    unused,
32    nonstandard_style,
33    future_incompatible,
34    missing_copy_implementations,
35    missing_debug_implementations,
36    missing_docs,
37    clippy::cargo,
38    clippy::complexity,
39    clippy::correctness,
40    clippy::perf,
41    clippy::style,
42    clippy::suspicious,
43    clippy::pedantic,
44    non_fmt_panics
45)]
46#![allow(clippy::multiple_crate_versions)]
47
48mod names;
49
50use names::ADJECTIVES;
51use names::NAMES;
52use rand::Rng;
53use rand::seq::IndexedRandom;
54
55/// Generate a readable name with some customization
56///
57/// # Examples
58///
59/// ```
60/// use anarchist_readable_name_generator_lib::readable_name_custom;
61/// use rand::prelude::*;
62/// use rand_chacha::ChaChaRng;
63///
64/// let rng = ChaChaRng::seed_from_u64(2);
65/// assert_eq!(
66///    readable_name_custom("+", rng),
67///    "romantic+kamalmaz"
68/// );
69/// ```
70///
71/// # Panics
72///
73/// Should not panic, would panic if there were no ADJECTIVES or if NAMES (both constants guaranteed not to be empty)
74#[must_use]
75pub fn readable_name_custom<R: Rng>(seperator: &str, mut rng: R) -> String {
76    format!(
77        "{}{}{}",
78        ADJECTIVES
79            .choose(&mut rng)
80            .expect("This should never fail, our list is predefined"),
81        seperator,
82        NAMES
83            .choose(&mut rng)
84            .expect("This should never fail, our list is predefined")
85    )
86}
87
88/// Generate a readable name with some customization and a random numeric suffix
89///
90/// # Examples
91///
92/// ```
93/// use anarchist_readable_name_generator_lib::{readable_name_custom_suffix};
94/// use rand::prelude::*;
95/// use rand_chacha::ChaChaRng;
96///
97/// let rng = ChaChaRng::seed_from_u64(2);
98/// assert_eq!(
99///    readable_name_custom_suffix("+", rng),
100///    "dynamic+lepper3"
101/// );
102/// ```
103///
104/// # Panics
105///
106/// Should not panic, would panic if there were no ADJECTIVES or if NAMES (both constants guaranteed not to be empty)
107#[must_use]
108pub fn readable_name_custom_suffix<R: Rng>(seperator: &str, mut rng: R) -> String {
109    let suffix = rng.random_range(0..=9);
110
111    format!("{}{}", readable_name_custom(seperator, &mut rng), suffix)
112}
113
114/// Generate a readable name with some customization
115///
116/// # Examples
117///
118/// ```
119/// use anarchist_readable_name_generator_lib::readable_name;
120///
121/// assert!(readable_name().len() > 0)
122/// ```
123#[must_use]
124pub fn readable_name() -> String {
125    let rng = rand::rng();
126    readable_name_custom("_", rng)
127}
128
129#[cfg(test)]
130mod test_readable_name_custom {
131    use super::{readable_name_custom, readable_name_custom_suffix};
132
133    use rand::prelude::*;
134    use rand_chacha::ChaChaRng;
135
136    #[test]
137    fn it_generates_a_name_with_a_custom_separator() {
138        let rng = rand::rng();
139        let split = readable_name_custom("-", rng)
140            .split('-')
141            .map(String::from)
142            .collect::<Vec<_>>();
143        assert!(!split.first().unwrap().is_empty());
144        assert!(!split.get(1).unwrap().is_empty());
145        assert_eq!(split.len(), 2);
146    }
147
148    #[test]
149    fn it_can_be_made_predictable_with_a_known_seed() {
150        let rng_1 = ChaChaRng::seed_from_u64(2);
151        let rng_2 = ChaChaRng::seed_from_u64(2);
152        assert_eq!(
153            readable_name_custom("_", rng_1),
154            readable_name_custom("_", rng_2)
155        );
156    }
157
158    #[test]
159    fn it_can_add_a_random_number_to_the_end_to_make_it_unique() {
160        let rng_1 = ChaChaRng::seed_from_u64(2);
161        assert_eq!(readable_name_custom_suffix("_", rng_1), "dynamic_lepper3");
162    }
163}
164
165#[cfg(doctest)]
166mod test_readme {
167    macro_rules! external_doc_test {
168        ($x:expr) => {
169            #[doc = $x]
170            unsafe extern "C" {}
171        };
172    }
173
174    external_doc_test!(include_str!("../README.md"));
175}