use crate::{codepoints::Codepoint, Translation};
use std::cmp::Ordering;
#[derive(Copy, Clone, Eq, PartialEq, Default, Hash)]
pub struct Options(pub(crate) u32);
macro_rules! options {
($(
$(#[$extra_meta:meta])*
$idx:literal: $name:ident,
)*) => {
$(
$(#[$extra_meta])*
#[cfg_attr(not(feature = "options"), cold)]
pub const fn $name(self) -> Self {
#[cfg(feature = "options")]
return Self(self.0 | (1 << $idx));
#[cfg(not(feature = "options"))]
return self;
}
)*
};
}
impl Options {
#[cfg_attr(not(feature = "options"), cold)]
pub const fn all() -> Self {
#[cfg(feature = "options")]
return Self(0x1ffffff);
#[cfg(not(feature = "options"))]
return Self(0);
}
#[cfg_attr(not(feature = "options"), cold)]
pub const fn pure_homoglyph() -> Self {
#[cfg(feature = "options")]
return Self(0x3ffffc);
#[cfg(not(feature = "options"))]
return Self(0);
}
options! {
0: retain_capitalization,
1: disable_bidi,
2: retain_diacritics,
3: retain_greek,
4: retain_cyrillic,
5: retain_hebrew,
6: retain_arabic,
7: retain_devanagari,
8: retain_bengali,
9: retain_armenian,
10: retain_gujarati,
11: retain_tamil,
12: retain_thai,
13: retain_lao,
14: retain_burmese,
15: retain_khmer,
16: retain_mongolian,
17: retain_chinese,
18: retain_japanese,
19: retain_korean,
20: retain_braille,
21: retain_emojis,
22: retain_turkish,
23: ascii_only,
24: alphanumeric_only,
}
#[cfg(feature = "options")]
pub(crate) const fn is(self, attribute_idx: u8) -> bool {
(self.0 & (1 << attribute_idx as u32)) != 0
}
#[cfg(feature = "options")]
pub(crate) const fn refuse_cure(self, attributes: u8) -> bool {
let locale = attributes >> 2;
((attributes & 1) != 0 && self.is(2))
|| ((attributes & 2) != 0 && self.is(22))
|| locale > 2 && self.is(locale)
}
pub(crate) fn translate(self, code: u32, offset: i32, mut end: i32) -> Option<Translation> {
let mut start = 0;
while start <= end {
let mid = (start + end) / 2;
let codepoint = Codepoint::at(offset + (mid * 6));
#[cfg(feature = "options")]
let ord = codepoint.matches(code, self)?;
#[cfg(not(feature = "options"))]
let ord = codepoint.matches(code)?;
match ord {
Ordering::Equal => return Some(codepoint.translation(code)),
Ordering::Greater => start = mid + 1,
Ordering::Less => end = mid - 1,
}
}
None
}
}
#[doc(hidden)]
#[cfg(feature = "options")]
impl From<u32> for Options {
#[inline(always)]
fn from(value: u32) -> Self {
Self(value)
}
}