use phf::phf_map;
use super::contraction::{ContractionMatch, ContractionRule, match_longest};
use crate::unicode::decode_unicode;
static LOWER_GROUPSIGNS: phf::Map<&'static str, u8> = phf_map! {
"en" => decode_unicode('⠢'),
"in" => decode_unicode('⠔'),
};
pub struct LowerGroupsignRule;
impl ContractionRule for LowerGroupsignRule {
fn try_match(&self, word: &[char], pos: usize) -> Option<ContractionMatch> {
match_longest(word, pos, &LOWER_GROUPSIGNS, 70)
}
}
pub(crate) static MIDDLE_LOWER_GROUPSIGNS: phf::Map<&'static str, u8> = phf_map! {
"ea" => decode_unicode('⠂'),
"bb" => decode_unicode('⠆'),
"cc" => decode_unicode('⠒'),
"ff" => decode_unicode('⠖'),
"gg" => decode_unicode('⠶'),
};
pub(crate) fn middle_lower_groupsign(word: &[char], pos: usize) -> Option<ContractionMatch> {
if pos == 0 || !word[pos - 1].is_alphabetic() {
return None;
}
let key: String = word.get(pos..pos + 2)?.iter().collect();
let &cell = MIDDLE_LOWER_GROUPSIGNS.get(key.as_str())?;
if !word.get(pos + 2).is_some_and(|c| c.is_alphabetic()) {
return None;
}
Some(ContractionMatch {
cells: vec![cell],
consumed: 2,
priority: 70,
protect_span: false,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[rstest::rstest]
#[case::en("en", 0, Some((decode_unicode('⠢'), 2)))]
#[case::in_word("find", 1, Some((decode_unicode('⠔'), 2)))]
#[case::no_match("cat", 0, None)]
fn matches_lower_groupsigns(
#[case] word: &str,
#[case] pos: usize,
#[case] expected: Option<(u8, usize)>,
) {
let chars: Vec<char> = word.chars().collect();
let got = LowerGroupsignRule
.try_match(&chars, pos)
.map(|m| (m.cells[0], m.consumed));
assert_eq!(got, expected);
}
#[test]
fn middle_lower_groupsign_rejects_runtime_word_final_pair() {
let chars: Vec<char> = std::hint::black_box("sea").chars().collect();
assert!(middle_lower_groupsign(&chars, std::hint::black_box(1)).is_none());
}
}