use rand::{thread_rng, RngCore};
#[derive(Debug, Clone, Copy)]
pub enum Alphabet {
Lowercase, Uppercase, Digits, Special, }
impl Alphabet {
fn expand(&self) -> &'static str {
match self {
Alphabet::Lowercase => "abcdefghijklmnopqrstuvwxyz",
Alphabet::Uppercase => "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
Alphabet::Digits => "0123456789",
Alphabet::Special => "-_",
}
}
}
#[derive(Debug)]
pub struct Error(String);
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl std::error::Error for Error {}
pub struct RandomStringGenerator {
base_character_set: String,
}
impl RandomStringGenerator {
pub fn new(alphabets: &[Alphabet]) -> Result<Self, Error> {
if alphabets.is_empty() {
return Err(Error(
"No valid characters provided for random string generation.".to_string(),
));
}
let base_character_set = alphabets
.iter()
.map(|a| a.expand())
.collect::<Vec<&str>>()
.join("");
Ok(Self { base_character_set })
}
pub fn generate(&self, length: usize, alphabet: Option<Alphabet>) -> Result<String, Error> {
if length == 0 {
return Err(Error("Length must be a positive integer.".to_string()));
}
let (character_set, char_set_length) = if let Some(alphabet) = alphabet {
let set = alphabet.expand();
(set, set.len())
} else {
(&self.base_character_set[..], self.base_character_set.len())
};
let mut rng = thread_rng();
let mut char_array = vec![0u8; length];
rng.fill_bytes(&mut char_array);
let result = char_array
.iter()
.map(|&byte| {
let index = byte as usize % char_set_length;
character_set.chars().nth(index).unwrap()
})
.collect();
Ok(result)
}
}