use alloc::{borrow::Cow, string::String};
use rand::seq::IndexedRandom;
use crate::{Generator, List, Lists, Namer, Words};
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Petnames<'a> {
pub adjectives: Words<'a>,
pub adverbs: Words<'a>,
pub nouns: Words<'a>,
}
impl<'a> Petnames<'a> {
#[cfg(feature = "default-words")]
pub fn small() -> Self {
crate::english!("words/small")
}
#[cfg(feature = "default-words")]
pub fn medium() -> Self {
crate::english!("words/medium")
}
#[cfg(feature = "default-words")]
pub fn large() -> Self {
crate::english!("words/large")
}
pub fn new(adjectives: &'a str, adverbs: &'a str, nouns: &'a str) -> Self {
Self {
adjectives: Cow::Owned(adjectives.split_whitespace().collect()),
adverbs: Cow::Owned(adverbs.split_whitespace().collect()),
nouns: Cow::Owned(nouns.split_whitespace().collect()),
}
}
pub fn retain<F>(&mut self, mut predicate: F)
where
F: FnMut(&str) -> bool,
{
self.adjectives.to_mut().retain(|word| predicate(word));
self.adverbs.to_mut().retain(|word| predicate(word));
self.nouns.to_mut().retain(|word| predicate(word));
}
pub fn cardinality(&self, words: u8) -> u128 {
Lists::new(words)
.map(|list| match list {
List::Adverb => self.adverbs.len() as u128,
List::Adjective => self.adjectives.len() as u128,
List::Noun => self.nouns.len() as u128,
})
.reduce(u128::saturating_mul)
.unwrap_or(0u128)
}
pub fn namer<'b>(&'b self, words: u8, separator: &'b str) -> Namer<'b, Self> {
Namer { generator: self, words, separator }
}
}
impl Generator for Petnames<'_> {
fn generate_into(&self, buf: &mut String, rng: &mut dyn rand::Rng, words: u8, separator: &str) {
for list in Lists::new(words) {
match list {
List::Adverb => {
if let Some(word) = self.adverbs.choose(rng).copied() {
buf.push_str(word);
buf.push_str(separator);
}
}
List::Adjective => {
if let Some(word) = self.adjectives.choose(rng).copied() {
buf.push_str(word);
buf.push_str(separator);
}
}
List::Noun => {
if let Some(word) = self.nouns.choose(rng).copied() {
buf.push_str(word);
}
}
};
}
}
}
#[cfg(feature = "default-words")]
impl Default for Petnames<'_> {
fn default() -> Self {
Self::medium()
}
}