include!(concat!(env!("OUT_DIR"), "/idna_tables.rs"));
#[inline]
pub(crate) fn in_range_table(c: char, table: &[(u32, u32)]) -> bool {
let cp = c as u32;
let i = table.partition_point(|&(lo, _)| lo <= cp);
if i == 0 {
return false;
}
let (_, hi) = table[i - 1];
cp <= hi
}
#[inline]
pub(crate) fn is_bidi_ignored_mark(c: char) -> bool {
in_range_table(c, BIDI_IGNORED)
}
#[inline]
pub(crate) fn is_joining_letter_cp(c: char) -> bool {
in_range_table(c, JOINING_LETTERS)
}
#[inline]
pub(crate) fn is_rtl_non_letter(c: char) -> bool {
in_range_table(c, RTL_NON_LETTERS)
}
#[inline]
pub(crate) fn is_rtl_alphabetic_block(c: char) -> bool {
in_range_table(c, RTL_ALPHABETIC)
}
#[inline]
pub(crate) fn is_bidi_number_cp(c: char) -> bool {
in_range_table(c, BIDI_NUMBERS)
}
#[inline]
pub(crate) fn is_legacy_arabic_cp(c: char) -> bool {
in_range_table(c, LEGACY_ARABIC)
}
#[inline]
pub(crate) fn is_disallowed_cp(c: char) -> bool {
in_range_table(c, DISALLOWED)
}
#[inline]
pub(crate) fn is_ltr_letter_block(c: char) -> bool {
in_range_table(c, LTR_LETTERS)
}
#[inline]
pub(crate) fn is_arabic_ext_b_letter_cp(c: char) -> bool {
in_range_table(c, ARABIC_EXT_B_LETTERS)
}
#[inline]
pub(crate) fn is_arabic_ext_b_compatible_cp(c: char) -> bool {
in_range_table(c, ARABIC_EXT_B_COMPATIBLE)
}
#[inline]
pub(crate) fn is_arabic_ext_b_era_mark_cp(c: char) -> bool {
in_range_table(c, ARABIC_EXT_B_ERA_MARKS)
}
#[inline]
pub(crate) fn is_arabic_ext_b_era_ok_cp(c: char) -> bool {
in_range_table(c, ARABIC_EXT_B_ERA_OK)
}
#[inline]
pub(crate) fn maps_nfkc_via_space_cp(c: char) -> bool {
in_range_table(c, NFKC_VIA_SPACE)
}
#[inline]
pub(crate) fn is_uts46_ignored_cp(c: char) -> bool {
in_range_table(c, UTS46_IGNORED)
}
#[inline]
pub(crate) fn uts46_needs_map_cp(c: char) -> bool {
in_range_table(c, UTS46_NEEDS_MAP)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn partition_point_membership() {
let table: &[(u32, u32)] = &[(0x0041, 0x005A), (0x0061, 0x007A), (0x00C0, 0x00FF)];
assert!(in_range_table('A', table));
assert!(in_range_table('Z', table));
assert!(!in_range_table('[', table));
assert!(in_range_table('a', table));
assert!(in_range_table('ü', table));
assert!(!in_range_table('Ѐ', table));
assert!(!in_range_table('\0', table));
}
#[test]
fn generated_bidi_ignored_spot_checks() {
assert!(is_bidi_ignored_mark('\u{0613}'));
assert!(is_bidi_ignored_mark('\u{0300}'));
assert!(is_bidi_ignored_mark('\u{FB1E}'));
assert!(!is_bidi_ignored_mark('\u{06DE}'));
assert!(!is_bidi_ignored_mark('\u{05BE}'));
assert!(is_bidi_ignored_mark('\u{112DF}'));
}
#[test]
fn generated_rtl_and_joining_spot_checks() {
assert!(is_rtl_non_letter('\u{05BE}'));
assert!(is_rtl_non_letter('\u{0888}'));
assert!(is_rtl_alphabetic_block('\u{05D0}'));
assert!(is_rtl_alphabetic_block('\u{1E900}'));
assert!(is_joining_letter_cp('\u{0627}'));
assert!(is_joining_letter_cp('\u{0710}'));
assert!(is_bidi_number_cp('\u{0660}'));
assert!(is_legacy_arabic_cp('\u{0627}'));
}
#[test]
fn generated_disallowed_and_map_spot_checks() {
assert!(is_disallowed_cp('\u{2028}'));
assert!(is_disallowed_cp('\u{0890}'));
assert!(is_disallowed_cp('\u{FE52}'));
assert!(!is_disallowed_cp('a'));
assert!(is_uts46_ignored_cp('\u{00AD}'));
assert!(is_uts46_ignored_cp('\u{1BCA0}'));
assert!(uts46_needs_map_cp('\u{00BC}'));
assert!(maps_nfkc_via_space_cp('\u{00A8}'));
assert!(is_arabic_ext_b_letter_cp('\u{088F}'));
assert!(!is_arabic_ext_b_letter_cp('\u{0888}'));
assert!(is_ltr_letter_block('ü'));
}
#[test]
fn tables_are_sorted_and_disjoint() {
for (name, table) in [
("BIDI_IGNORED", BIDI_IGNORED),
("JOINING_LETTERS", JOINING_LETTERS),
("RTL_NON_LETTERS", RTL_NON_LETTERS),
("RTL_ALPHABETIC", RTL_ALPHABETIC),
("BIDI_NUMBERS", BIDI_NUMBERS),
("LEGACY_ARABIC", LEGACY_ARABIC),
("DISALLOWED", DISALLOWED),
("LTR_LETTERS", LTR_LETTERS),
("ARABIC_EXT_B_LETTERS", ARABIC_EXT_B_LETTERS),
("ARABIC_EXT_B_COMPATIBLE", ARABIC_EXT_B_COMPATIBLE),
("ARABIC_EXT_B_ERA_MARKS", ARABIC_EXT_B_ERA_MARKS),
("ARABIC_EXT_B_ERA_OK", ARABIC_EXT_B_ERA_OK),
("NFKC_VIA_SPACE", NFKC_VIA_SPACE),
("UTS46_IGNORED", UTS46_IGNORED),
("UTS46_NEEDS_MAP", UTS46_NEEDS_MAP),
] {
assert!(!table.is_empty(), "{name} empty");
for window in table.windows(2) {
let (a_lo, a_hi) = window[0];
let (b_lo, _) = window[1];
assert!(a_lo <= a_hi, "{name}: inverted {a_lo:04X}..={a_hi:04X}");
assert!(
a_hi.saturating_add(1) < b_lo,
"{name}: overlap/adjacent {a_lo:04X}..={a_hi:04X} vs {b_lo:04X}"
);
}
}
}
}