use std::collections::{HashMap, VecDeque};
use std::str;
pub struct Alphabet {
pub next_char_map: HashMap<char, Option<char>>,
pub first_char: char,
}
pub struct WordsIterator<'a> {
pub alphabet: &'a Alphabet,
max_len: Option<usize>,
next_item: String,
}
impl Alphabet {
pub fn from_chars_in_str<T: AsRef<str>>(alphabet_str: T) -> Result<Self, String> {
let mut next_char_map = HashMap::new();
let mut first_char: Option<char> = None;
let mut previous_char: Option<char> = None;
for c in alphabet_str.as_ref().chars() {
if first_char.is_none() {
first_char = Some(c);
previous_char = Some(c);
} else if previous_char.is_some()
&& previous_char.unwrap() != c
&& !next_char_map.contains_key(&c)
{
next_char_map.insert(previous_char.unwrap(), Some(c));
previous_char = Some(c);
}
}
if let Some(pc) = previous_char {
next_char_map.entry(pc).or_insert(None);
}
if next_char_map.keys().len() < 2 {
return Err(String::from(
"Invalid alphabet string. Found less than 2 unique chars",
));
}
Ok(Alphabet {
next_char_map,
first_char: first_char.unwrap(),
})
}
pub fn all_words(&self, max_len: Option<usize>) -> WordsIterator {
WordsIterator {
alphabet: self,
max_len,
next_item: String::from(self.first_char),
}
}
pub fn all_words_unbound(&self) -> WordsIterator {
WordsIterator {
alphabet: self,
max_len: None,
next_item: String::from(self.first_char),
}
}
pub fn all_words_starting_from(
&self,
start_word: String,
max_len: Option<usize>,
) -> WordsIterator {
WordsIterator {
alphabet: self,
max_len,
next_item: start_word,
}
}
pub fn all_words_with_len(&self, start_len: usize, max_len: Option<usize>) -> WordsIterator {
WordsIterator {
alphabet: self,
max_len,
next_item: (0..start_len).map(|_| self.first_char).collect::<String>(),
}
}
}
impl<'a> Iterator for WordsIterator<'a> {
type Item = String;
fn next(&mut self) -> Option<String> {
if self.max_len.is_some() && self.max_len.unwrap() < self.next_item.len() {
return None;
}
let current_item = self.next_item.clone();
let mut next_item: VecDeque<char> = VecDeque::with_capacity(current_item.len() + 1);
let mut carry = true;
for c in current_item.chars().rev() {
if carry {
let next_char = self.alphabet.next_char_map.get(&c).unwrap_or(&None);
let next_char = match next_char {
Some(c) => {
carry = false;
*c
}
None => {
carry = true;
self.alphabet.first_char
}
};
next_item.push_front(next_char);
} else {
next_item.push_front(c);
}
}
if carry {
next_item.push_front(self.alphabet.first_char);
}
let next_item: String = next_item.iter().collect();
self.next_item = next_item;
Some(current_item)
}
}
impl str::FromStr for Alphabet {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Alphabet::from_chars_in_str(&String::from(s))
}
}
#[cfg(test)]
mod test;