use super::insert_unique;
use std::collections::HashMap;
use std::sync::OnceLock;
#[derive(Clone, Copy)]
pub struct BengaliVowel {
pub independent: &'static str,
pub dependent: Option<&'static str>,
}
impl BengaliVowel {
pub const fn new(independent: &'static str, dependent: Option<&'static str>) -> Self {
Self {
independent,
dependent,
}
}
}
pub type VowelRule = (&'static str, BengaliVowel);
pub(crate) const MAX_VOWEL_RULE_BYTES: usize = 3;
const VOWEL_RULES: &[VowelRule] = &[
("o", BengaliVowel::new("অ", None)),
("A", BengaliVowel::new("আ", Some("া"))),
("AY", BengaliVowel::new("অ্যা", Some("্যা"))),
("ai", BengaliVowel::new("আই", Some("াই"))),
("au", BengaliVowel::new("আউ", Some("াউ"))),
("ae", BengaliVowel::new("আএ", Some("াএ"))),
("ao", BengaliVowel::new("আও", Some("াও"))),
("ia", BengaliVowel::new("ইয়া", Some("িয়া"))),
("io", BengaliVowel::new("ইও", Some("িও"))),
("eo", BengaliVowel::new("এও", Some("েও"))),
("a", BengaliVowel::new("আ", Some("া"))),
("aY", BengaliVowel::new("অ্যা", Some("্যা"))),
("i", BengaliVowel::new("ই", Some("ি"))),
("I", BengaliVowel::new("ঈ", Some("ী"))),
("u", BengaliVowel::new("উ", Some("ু"))),
("U", BengaliVowel::new("ঊ", Some("ূ"))),
("e", BengaliVowel::new("এ", Some("ে"))),
("E", BengaliVowel::new("এ", Some("ে"))),
("OI", BengaliVowel::new("ঐ", Some("ৈ"))),
("O", BengaliVowel::new("ও", Some("ো"))),
("OU", BengaliVowel::new("ঔ", Some("ৌ"))),
("rri", BengaliVowel::new("ঋ", Some("ৃ"))),
];
fn build_vowels() -> HashMap<&'static str, BengaliVowel> {
let mut map = HashMap::with_capacity(VOWEL_RULES.len());
for &(roman, vowel) in VOWEL_RULES {
insert_unique(&mut map, "vowel", roman, vowel);
}
map
}
pub const fn vowel_rules() -> &'static [VowelRule] {
VOWEL_RULES
}
pub fn vowel_value(roman: &str) -> Option<BengaliVowel> {
match roman {
"o" => Some(BengaliVowel::new("অ", None)),
"A" => Some(BengaliVowel::new("আ", Some("া"))),
"AY" => Some(BengaliVowel::new("অ্যা", Some("্যা"))),
"ai" => Some(BengaliVowel::new("আই", Some("াই"))),
"au" => Some(BengaliVowel::new("আউ", Some("াউ"))),
"ae" => Some(BengaliVowel::new("আএ", Some("াএ"))),
"ao" => Some(BengaliVowel::new("আও", Some("াও"))),
"ia" => Some(BengaliVowel::new("ইয়া", Some("িয়া"))),
"io" => Some(BengaliVowel::new("ইও", Some("িও"))),
"eo" => Some(BengaliVowel::new("এও", Some("েও"))),
"a" => Some(BengaliVowel::new("আ", Some("া"))),
"aY" => Some(BengaliVowel::new("অ্যা", Some("্যা"))),
"i" => Some(BengaliVowel::new("ই", Some("ি"))),
"I" => Some(BengaliVowel::new("ঈ", Some("ী"))),
"u" => Some(BengaliVowel::new("উ", Some("ু"))),
"U" => Some(BengaliVowel::new("ঊ", Some("ূ"))),
"e" | "E" => Some(BengaliVowel::new("এ", Some("ে"))),
"OI" => Some(BengaliVowel::new("ঐ", Some("ৈ"))),
"O" => Some(BengaliVowel::new("ও", Some("ো"))),
"OU" => Some(BengaliVowel::new("ঔ", Some("ৌ"))),
"rri" => Some(BengaliVowel::new("ঋ", Some("ৃ"))),
_ => None,
}
}
pub fn is_vowel(roman: &str) -> bool {
vowel_value(roman).is_some()
}
pub fn vowels_static() -> &'static HashMap<&'static str, BengaliVowel> {
static INSTANCE: OnceLock<HashMap<&'static str, BengaliVowel>> = OnceLock::new();
INSTANCE.get_or_init(build_vowels)
}
pub fn vowels() -> HashMap<&'static str, BengaliVowel> {
vowels_static().clone()
}
pub fn independent_vowels() -> HashMap<&'static str, &'static str> {
let mut map = HashMap::new();
for (key, value) in vowels_static().iter() {
map.insert(*key, value.independent);
}
map
}
pub fn vowel_modifiers() -> HashMap<&'static str, &'static str> {
let mut map = HashMap::new();
for (key, value) in vowels_static().iter() {
if let Some(dependent) = value.dependent {
map.insert(*key, dependent);
}
}
map
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn max_vowel_rule_bytes_matches_rule_table() {
assert!(
VOWEL_RULES.iter().all(|(roman, _)| roman.is_ascii()),
"vowel rule keys are byte-scanned ASCII signals"
);
assert_eq!(
MAX_VOWEL_RULE_BYTES,
VOWEL_RULES
.iter()
.map(|(roman, _)| roman.len())
.max()
.expect("vowel rule table should not be empty")
);
}
}