mod cmu;
mod nemeth;
use std::fmt;
use std::str::FromStr;
use crate::locale::Locale;
use crate::tree::Node;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BrailleCode {
Cmu,
Nemeth,
}
impl BrailleCode {
pub const ALL: [BrailleCode; 2] = [BrailleCode::Cmu, BrailleCode::Nemeth];
pub fn code(self) -> &'static str {
match self {
BrailleCode::Cmu => "cmu",
BrailleCode::Nemeth => "nemeth",
}
}
pub fn for_locale(locale: Locale) -> BrailleCode {
match locale {
Locale::PtBr | Locale::Es => BrailleCode::Cmu,
_ => BrailleCode::Nemeth,
}
}
}
impl fmt::Display for BrailleCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.code())
}
}
impl FromStr for BrailleCode {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_ascii_lowercase().as_str() {
"cmu" => Ok(BrailleCode::Cmu),
"nemeth" => Ok(BrailleCode::Nemeth),
other => Err(format!("unknown braille code: {other} (use cmu or nemeth)")),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct Braille {
pub text: String,
pub missing: Vec<char>,
}
pub fn transcribe(node: &Node, code: BrailleCode) -> Braille {
match code {
BrailleCode::Cmu => cmu::transcribe(node),
BrailleCode::Nemeth => nemeth::transcribe(node),
}
}
pub(crate) fn cell(dots: &str) -> char {
let bits = dots.chars().filter_map(|d| d.to_digit(10)).filter(|d| (1..=8).contains(d)).fold(0u32, |acc, d| acc | 1 << (d - 1));
char::from_u32(0x2800 + bits).expect("a braille pattern")
}
pub(crate) fn cells(dots: &str) -> String {
dots.split_whitespace().map(cell).collect()
}
pub(crate) fn letter(c: char) -> Option<&'static str> {
Some(match c.to_ascii_lowercase() {
'a' => "1",
'b' => "12",
'c' => "14",
'd' => "145",
'e' => "15",
'f' => "124",
'g' => "1245",
'h' => "125",
'i' => "24",
'j' => "245",
'k' => "13",
'l' => "123",
'm' => "134",
'n' => "1345",
'o' => "135",
'p' => "1234",
'q' => "12345",
'r' => "1235",
's' => "234",
't' => "2345",
'u' => "136",
'v' => "1236",
'w' => "2456",
'x' => "1346",
'y' => "13456",
'z' => "1356",
_ => return None,
})
}