use std::iter::range_inclusive;
use std::cmp::min;
use std::collections::HashMap;
pub type Config = Vec<(String, char)>;
type WordInProgress = Vec<char>;
pub fn default_config() -> Config {
range_inclusive(b'A', b'Z')
.map(|b|
((b - b'A' + 1).to_string(),
b as char))
.collect()
}
pub struct Parser {
max_lookahead: uint,
table: HashMap<Vec<char>, char>
}
impl Parser {
pub fn new(config: &Config) -> Parser {
Parser {
max_lookahead: config
.iter()
.map(|&(ref s, _)|
s.len()) .max_by(|&n| n)
.unwrap_or(0),
table: config
.iter()
.map(|&(ref s, c)| (s.as_slice().chars().collect(), c))
.collect()
}
}
pub fn parse(&self, digits: &str) -> Vec<String> {
let v = digits.chars().collect::<Vec<char>>();
let parsed = self.parse_list(v.as_slice());
parsed
.into_iter()
.map(|char_list| {
let chars = char_list
.into_iter()
.rev()
.collect::<Vec<char>>();
String::from_chars(chars.as_slice())
})
.collect()
}
fn parse_list(&self, ds: &[char]) -> Vec<WordInProgress> {
match ds {
[] => vec![vec![]],
_ => {
let max_lookahead_index = min(self.max_lookahead, ds.len());
let prefix = ds.slice_to(max_lookahead_index);
range_inclusive(1u, max_lookahead_index)
.flat_map(|lookahead_index| {
let unparsed_index = min(lookahead_index,
max_lookahead_index);
let token_slice = prefix.slice_to(unparsed_index);
let token = token_slice.to_vec();
self.table.get(&token).map_or_else(
|| vec![],
|&c| {
let unparsed = ds.slice_from(unparsed_index);
self.parse_list(unparsed)
.into_iter()
.map(|mut s| {
s.push(c);
s
})
.collect::<Vec<WordInProgress>>()
}
)
.into_iter()
})
.collect()
}
}
}
}
#[cfg(test)]
mod test {
use super::default_config;
use super::Parser;
use std::collections::HashSet;
#[test]
fn it_works() {
let parser = Parser::new(&default_config());
let expected = ["ABCD", "AWD", "LCD"];
let expected_set = expected
.iter()
.map(|&s| s)
.collect::<HashSet<&str>>();
let actual = parser.parse("1234");
let actual_set = actual
.iter()
.map(|s| s.as_slice())
.collect::<HashSet<&str>>();
assert_eq!(actual_set, expected_set)
}
}