use rand_core::RngCore;
pub const ADJ: [&str; 64] = [
"amber", "bold", "brave", "brisk", "calm", "cheery", "chill", "civil",
"clever", "cosy", "crisp", "daring", "deft", "dewy", "eager", "early",
"fancy", "fiery", "fleet", "fond", "frank", "free", "fresh", "gentle",
"giddy", "glad", "golden", "grand", "happy", "hardy", "hasty", "honest",
"humble", "jolly", "keen", "kind", "lively", "loyal", "lucky", "lunar",
"mellow", "merry", "mighty", "misty", "neat", "noble", "perky", "plucky",
"polar", "proud", "quick", "quiet", "rapid", "rosy", "royal", "shiny",
"snappy", "solid", "spry", "stout", "sunny", "swift", "tidy", "witty",
];
pub const ANIMAL: [&str; 64] = [
"otter", "panda", "falcon", "lynx", "koala", "heron", "fox", "ibex",
"marten", "tapir", "badger", "beaver", "bison", "bongo", "camel", "civet",
"condor", "crane", "dingo", "dove", "eland", "ermine", "ferret", "finch",
"gecko", "gibbon", "hare", "hawk", "hyrax", "jackal", "kestrel", "kiwi",
"lemur", "llama", "macaw", "magpie", "mole", "moose", "murre", "newt",
"ocelot", "okapi", "oriole", "osprey", "owl", "pika", "plover", "puffin",
"quokka", "rabbit", "raven", "robin", "seal", "shrew", "skink", "sparrow",
"stoat", "swan", "tern", "toucan", "vole", "wombat", "wren", "zebra",
];
#[allow(dead_code)]
pub const EXTRA: [&str; 16] = [
"azure", "cobalt", "coral", "crimson", "emerald", "hazel", "indigo", "ivory",
"jade", "lilac", "olive", "rose", "ruby", "scarlet", "teal", "violet",
];
fn pick<'a>(rng: &mut impl RngCore, list: &[&'a str]) -> &'a str {
let n = list.len() as u32;
debug_assert!(n.is_power_of_two(), "lists must be powers of two for unbiased pick");
let mask = n - 1;
list[(rng.next_u32() & mask) as usize]
}
pub fn mint_words() -> String {
let mut rng = super::os_rng();
format!("{}-{}", pick(&mut rng, &ADJ), pick(&mut rng, &ANIMAL))
}
pub fn mint_words_with(rng: &mut impl RngCore) -> String {
format!("{}-{}", pick(rng, &ADJ), pick(rng, &ANIMAL))
}
pub fn mint_nameplate() -> String {
let mut rng = super::os_rng();
format!("{}", 1000 + (rng.next_u32() % 9000))
}
pub fn mint_spoken_code() -> String {
format!("{}-{}", mint_words(), mint_nameplate())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn lists_are_unique_and_sized() {
use std::collections::HashSet;
assert_eq!(ADJ.len(), 64);
assert_eq!(ANIMAL.len(), 64);
assert_eq!(EXTRA.len(), 16);
assert_eq!(ADJ.iter().collect::<HashSet<_>>().len(), 64);
assert_eq!(ANIMAL.iter().collect::<HashSet<_>>().len(), 64);
assert_eq!(EXTRA.iter().collect::<HashSet<_>>().len(), 16);
assert_eq!(ADJ.len() * ANIMAL.len(), 1 << 12);
}
#[test]
fn minted_words_are_two_parts() {
let w = mint_words();
let parts: Vec<&str> = w.split('-').collect();
assert_eq!(parts.len(), 2, "adj-animal");
let full = mint_spoken_code();
assert_eq!(full.split('-').count(), 3, "adj-animal-NNNN");
}
}