use crate::iso_tables;
use std::collections::BTreeMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum CharClass {
Alpha,
Upper,
Lower,
Alnum,
Digit,
XDigit,
}
impl CharClass {
pub(crate) fn matches(self, value: char, case_sensitive: bool) -> bool {
match self {
Self::Alpha => value.is_ascii_alphabetic(),
Self::Upper => {
if case_sensitive {
value.is_ascii_uppercase()
} else {
value.is_ascii_alphabetic()
}
}
Self::Lower => {
if case_sensitive {
value.is_ascii_lowercase()
} else {
value.is_ascii_alphabetic()
}
}
Self::Alnum => value.is_ascii_alphanumeric(),
Self::Digit => value.is_ascii_digit(),
Self::XDigit => value.is_ascii_hexdigit(),
}
}
}
pub(crate) enum Resolved<'a> {
Class(CharClass),
Table {
exact: &'static [&'static str],
lower: &'static [&'static str],
lengths: &'static [usize],
},
Custom(&'a [String]),
}
pub(crate) const PREDEFINED: &[&str] = &[
"alpha", "upper", "lower", "alnum", "digit", "xdigit", "region", "lang",
];
pub(crate) const ISO_TABLE_SOURCE: &str = iso_tables::SOURCE;
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub(crate) struct SubstitutionTable {
custom: BTreeMap<String, Vec<String>>,
}
impl SubstitutionTable {
pub(crate) fn from_custom(custom: BTreeMap<String, Vec<String>>) -> Self {
Self { custom }
}
pub(crate) fn is_predefined(name: &str) -> bool {
PREDEFINED.contains(&name)
}
pub(crate) fn resolve(&self, name: &str) -> Option<Resolved<'_>> {
if let Some(values) = self.custom.get(name) {
return Some(Resolved::Custom(values));
}
Some(match name {
"alpha" => Resolved::Class(CharClass::Alpha),
"upper" => Resolved::Class(CharClass::Upper),
"lower" => Resolved::Class(CharClass::Lower),
"alnum" => Resolved::Class(CharClass::Alnum),
"digit" => Resolved::Class(CharClass::Digit),
"xdigit" => Resolved::Class(CharClass::XDigit),
"region" => Resolved::Table {
exact: iso_tables::REGIONS,
lower: iso_tables::REGIONS_LOWER,
lengths: iso_tables::REGIONS_LENGTHS,
},
"lang" => Resolved::Table {
exact: iso_tables::LANGS,
lower: iso_tables::LANGS_LOWER,
lengths: iso_tables::LANGS_LENGTHS,
},
_ => return None,
})
}
}