blob: 992aac1f857a5b528e5b8f140ac6a6d0380607d2 [file] [log] [blame]
use crate::{fmt_list, UnicodeData};
use std::fmt;
pub(crate) fn generate_case_mapping(data: &UnicodeData) -> String {
let mut file = String::new();
file.push_str(HEADER.trim_start());
let decl_type = "&[(char, [char; 3])]";
file.push_str(&format!(
"static LOWERCASE_TABLE: {} = &[{}];",
decl_type,
fmt_list(data.to_lower.iter().map(to_mapping))
));
file.push_str("\n\n");
file.push_str(&format!(
"static UPPERCASE_TABLE: {} = &[{}];",
decl_type,
fmt_list(data.to_upper.iter().map(to_mapping))
));
file
}
fn to_mapping((key, (a, b, c)): (&u32, &(u32, u32, u32))) -> (CharEscape, [CharEscape; 3]) {
(
CharEscape(std::char::from_u32(*key).unwrap()),
[
CharEscape(std::char::from_u32(*a).unwrap()),
CharEscape(std::char::from_u32(*b).unwrap()),
CharEscape(std::char::from_u32(*c).unwrap()),
],
)
}
struct CharEscape(char);
impl fmt::Debug for CharEscape {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "'{}'", self.0.escape_default())
}
}
static HEADER: &str = r"
pub fn to_lower(c: char) -> [char; 3] {
if c.is_ascii() {
[(c as u8).to_ascii_lowercase() as char, '\0', '\0']
} else {
match bsearch_case_table(c, LOWERCASE_TABLE) {
None => [c, '\0', '\0'],
Some(index) => LOWERCASE_TABLE[index].1,
}
}
}
pub fn to_upper(c: char) -> [char; 3] {
if c.is_ascii() {
[(c as u8).to_ascii_uppercase() as char, '\0', '\0']
} else {
match bsearch_case_table(c, UPPERCASE_TABLE) {
None => [c, '\0', '\0'],
Some(index) => UPPERCASE_TABLE[index].1,
}
}
}
fn bsearch_case_table(c: char, table: &[(char, [char; 3])]) -> Option<usize> {
table.binary_search_by(|&(key, _)| key.cmp(&c)).ok()
}
";