use phf::phf_map;
use super::contraction::{ContractionMatch, ContractionRule};
use crate::unicode::decode_unicode;
static INITIAL_CONTRACTIONS: phf::Map<&'static str, [u8; 2]> = phf_map! {
"right" => [decode_unicode('⠐'), decode_unicode('⠗')],
"question" => [decode_unicode('⠐'), decode_unicode('⠟')],
"character" => [decode_unicode('⠐'), decode_unicode('⠡')],
"through" => [decode_unicode('⠐'), decode_unicode('⠹')],
"ought" => [decode_unicode('⠐'), decode_unicode('⠳')],
"whose" => [decode_unicode('⠘'), decode_unicode('⠱')],
"word" => [decode_unicode('⠘'), decode_unicode('⠺')],
"cannot" => [decode_unicode('⠸'), decode_unicode('⠉')],
"spirit" => [decode_unicode('⠸'), decode_unicode('⠎')],
"world" => [decode_unicode('⠸'), decode_unicode('⠺')],
"many" => [decode_unicode('⠸'), decode_unicode('⠍')],
};
pub struct InitialContractionRule;
impl ContractionRule for InitialContractionRule {
fn try_match(&self, word: &[char], pos: usize) -> Option<ContractionMatch> {
let mut best: Option<(usize, [u8; 2])> = None;
for (key, &cells) in INITIAL_CONTRACTIONS.entries() {
let klen = key.chars().count();
if pos + klen <= word.len()
&& key
.chars()
.zip(&word[pos..pos + klen])
.all(|(k, w)| k == *w)
&& best.is_none_or(|(bl, _)| klen > bl)
{
best = Some((klen, cells));
}
}
best.map(|(klen, cells)| ContractionMatch {
cells: cells.to_vec(),
consumed: klen,
priority: 55,
protect_span: false,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[rstest::rstest]
#[case::right_mid("brighten", 1, Some((vec![decode_unicode('⠐'), decode_unicode('⠗')], 5)))]
#[case::spirit_mid("dispirited", 2, Some((vec![decode_unicode('⠸'), decode_unicode('⠎')], 6)))]
#[case::cannot("cannot", 0, Some((vec![decode_unicode('⠸'), decode_unicode('⠉')], 6)))]
#[case::character("characterise", 0, Some((vec![decode_unicode('⠐'), decode_unicode('⠡')], 9)))]
#[case::through("throughout", 0, Some((vec![decode_unicode('⠐'), decode_unicode('⠹')], 7)))]
#[case::no_match("cat", 0, None)]
fn matches_initial_contractions(
#[case] word: &str,
#[case] pos: usize,
#[case] expected: Option<(Vec<u8>, usize)>,
) {
let chars: Vec<char> = word.chars().collect();
let got = InitialContractionRule
.try_match(&chars, pos)
.map(|m| (m.cells, m.consumed));
assert_eq!(got, expected);
}
}