use rand::Rng;
const FIRST_NAME_STARTS: &[&str] = &[
"Al", "An", "Br", "Ch", "Da", "Ed", "El", "Er", "Fr", "Ge", "Ja", "Jo", "Ka", "Ke", "La", "Ma",
"Mi", "Ni", "Pa", "Ra", "Ri", "Ro", "Sa", "Sh", "St", "Ta", "Th", "Tr", "Wi", "Za",
];
const FIRST_NAME_MIDDLES: &[&str] = &[
"an", "ar", "el", "en", "er", "es", "ic", "in", "is", "it", "on", "or", "ow", "un", "us", "al",
"am", "at", "ed", "ol",
];
const FIRST_NAME_ENDS: &[&str] = &[
"a", "an", "el", "en", "er", "es", "ia", "ic", "ie", "in", "is", "on", "or", "us", "yn", "ah",
"am", "as", "ed", "em", "ey", "im", "le", "ol", "ry", "ty",
];
const LAST_NAME_STARTS: &[&str] = &[
"Ba", "Be", "Br", "Ca", "Ch", "Cl", "Co", "Cr", "Da", "De", "Di", "Do", "Dr", "El", "Ev", "Fa",
"Fi", "Fr", "Ga", "Ge", "Gi", "Gr", "Ha", "He", "Hi", "Ho", "Hu", "Ja", "Jo", "Ka", "Ke", "Ki",
"Kn", "La", "Le", "Li", "Lo", "Lu", "Ma", "Mc", "Me", "Mi", "Mo", "Mu", "Na", "Ne", "Ni", "No",
"O'", "Ol", "Or", "Pa", "Pe", "Ph", "Pi", "Po", "Pr", "Qu", "Ra", "Re", "Ri", "Ro", "Ru", "Sa",
"Sc", "Se", "Sh", "Si", "Sk", "Sl", "Sm", "Sn", "So", "Sp", "St", "Su", "Sw", "Ta", "Te", "Th",
"Ti", "To", "Tr", "Tu", "Ty", "Un", "Va", "Vi", "Wa", "We", "Wh", "Wi", "Wo", "Wr", "Ya", "Ye",
"Yo", "Za",
];
const LAST_NAME_MIDDLES: &[&str] = &[
"al", "an", "ar", "as", "at", "ay", "el", "en", "er", "es", "et", "ey", "ic", "id", "il", "in",
"is", "it", "le", "li", "lo", "ly", "ma", "me", "mi", "mo", "na", "ne", "ni", "no", "ol", "on",
"or", "os", "ot", "ow", "ra", "re", "ri", "ro", "ry", "sa", "se", "si", "so", "st", "ta", "te",
"ti", "to", "tr", "ty", "ul", "un", "ur", "us", "ut", "wa", "we", "wi", "wo", "ya", "ye", "yo",
];
const LAST_NAME_ENDS: &[&str] = &[
"an", "ar", "as", "ay", "ed", "el", "en", "er", "es", "et", "ey", "ia", "ic", "id", "ie", "in",
"is", "it", "le", "ly", "ma", "me", "mi", "mo", "na", "ne", "ni", "no", "ns", "nt", "ol", "om",
"on", "or", "os", "ot", "ow", "ra", "rd", "re", "rk", "rl", "rm", "rn", "ro", "rs", "rt", "ry",
"se", "sh", "si", "sk", "sm", "sn", "so", "sp", "ss", "st", "te", "th", "ti", "to", "ts", "ty",
"ul", "un", "ur", "us", "ut", "wa", "we", "wi", "wn", "ws", "ya", "ye", "yo", "ys", "za",
];
pub fn generate_first_name() -> String {
let mut rng = rand::thread_rng();
let mut name = String::new();
name.push_str(FIRST_NAME_STARTS[rng.gen_range(0..FIRST_NAME_STARTS.len())]);
if rng.gen_bool(0.7) {
name.push_str(FIRST_NAME_MIDDLES[rng.gen_range(0..FIRST_NAME_MIDDLES.len())]);
}
if rng.gen_bool(0.4) && name.len() < 8 {
name.push_str(FIRST_NAME_MIDDLES[rng.gen_range(0..FIRST_NAME_MIDDLES.len())]);
}
name.push_str(FIRST_NAME_ENDS[rng.gen_range(0..FIRST_NAME_ENDS.len())]);
name = name
.chars()
.enumerate()
.map(|(i, c)| {
if i == 0 {
c.to_uppercase().collect::<String>()
} else {
c.to_lowercase().collect::<String>()
}
})
.collect();
name
}
pub fn generate_last_name() -> String {
let mut rng = rand::thread_rng();
let mut name = String::new();
name.push_str(LAST_NAME_STARTS[rng.gen_range(0..LAST_NAME_STARTS.len())]);
if rng.gen_bool(0.8) {
name.push_str(LAST_NAME_MIDDLES[rng.gen_range(0..LAST_NAME_MIDDLES.len())]);
}
if rng.gen_bool(0.5) && name.len() < 10 {
name.push_str(LAST_NAME_MIDDLES[rng.gen_range(0..LAST_NAME_MIDDLES.len())]);
}
name.push_str(LAST_NAME_ENDS[rng.gen_range(0..LAST_NAME_ENDS.len())]);
if name.starts_with("Mc") || name.starts_with("O'") {
let mut chars: Vec<char> = name.chars().collect();
if !chars.is_empty() {
chars[0] = chars[0].to_uppercase().next().unwrap();
}
if chars.len() > 2 {
chars[2] = chars[2].to_uppercase().next().unwrap();
}
for (i, char_ref) in chars.iter_mut().enumerate().skip(1) {
if i != 2 {
*char_ref = char_ref.to_lowercase().next().unwrap();
}
}
name = chars.into_iter().collect();
} else {
name = name
.chars()
.enumerate()
.map(|(i, c)| {
if i == 0 {
c.to_uppercase().collect::<String>()
} else {
c.to_lowercase().collect::<String>()
}
})
.collect();
}
name
}
pub fn generate_full_name() -> String {
format!("{} {}", generate_first_name(), generate_last_name())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_generate_first_name() {
let name = generate_first_name();
assert!(!name.is_empty());
assert!(name.len() >= 2);
assert!(name.chars().next().unwrap().is_uppercase());
}
#[test]
fn test_generate_last_name() {
let name = generate_last_name();
assert!(!name.is_empty());
assert!(name.len() >= 2);
assert!(name.chars().next().unwrap().is_uppercase());
}
#[test]
fn test_generate_full_name() {
let name = generate_full_name();
let parts: Vec<&str> = name.split_whitespace().collect();
assert_eq!(parts.len(), 2);
assert!(!parts[0].is_empty());
assert!(!parts[1].is_empty());
}
#[test]
fn test_multiple_names_are_different() {
let name1 = generate_full_name();
let name2 = generate_full_name();
let name3 = generate_full_name();
let all_same = name1 == name2 && name2 == name3;
assert!(!all_same);
}
#[test]
fn test_name_generation_produces_variety() {
let mut names = Vec::new();
for _ in 0..20 {
names.push(generate_first_name());
}
let unique_count = names.iter().collect::<std::collections::HashSet<_>>().len();
assert!(unique_count > 5, "Should generate variety of names");
}
}