#[cfg(feature = "gb18030")]
use crate::tables::gb18030::GB18030_RANGES;
#[cfg(any(
feature = "euc-jp",
feature = "euc-kr",
feature = "gb18030",
feature = "iso-2022-jp",
feature = "shift-jis"
))]
#[inline]
pub(crate) fn code_point(table: &[u16], pointer: usize) -> Option<u32> {
match table.get(pointer).copied() {
None | Some(0) => None,
Some(cp) => Some(u32::from(cp)),
}
}
#[cfg(feature = "big5")]
#[inline]
pub(crate) fn code_point_wide(table: &[u32], pointer: usize) -> Option<u32> {
match table.get(pointer).copied() {
None | Some(0) => None,
Some(cp) => Some(cp),
}
}
#[inline]
fn bucket(buckets: &[u16; 258], scalar: u32) -> core::ops::Range<usize> {
let high = core::cmp::min(scalar >> 8, 0x100) as usize;
usize::from(buckets[high])..usize::from(buckets[high + 1])
}
#[cfg(any(
feature = "euc-jp",
feature = "euc-kr",
feature = "gb18030",
feature = "iso-2022-jp",
feature = "shift-jis"
))]
#[inline]
pub(crate) fn pointer(
code_points: &[u16],
pointers: &[u16],
buckets: &[u16; 258],
scalar: u32,
) -> Option<u16> {
if scalar > 0xFFFF {
return None;
}
let range = bucket(buckets, scalar);
let found = code_points[range.clone()]
.binary_search(&(scalar as u16))
.ok()?;
pointers.get(range.start + found).copied()
}
#[cfg(feature = "big5")]
#[inline]
pub(crate) fn pointer_wide(
code_points: &[u32],
pointers: &[u16],
buckets: &[u16; 258],
scalar: u32,
) -> Option<u16> {
let range = bucket(buckets, scalar);
let found = code_points[range.clone()].binary_search(&scalar).ok()?;
pointers.get(range.start + found).copied()
}
#[cfg(feature = "gb18030")]
pub(crate) fn gb18030_ranges_code_point(pointer: u32) -> Option<u32> {
if (pointer > 39419 && pointer < 189_000) || pointer > 1_237_575 {
return None;
}
if pointer == 7457 {
return Some(0xE7C7);
}
let i = GB18030_RANGES
.partition_point(|&(p, _)| p <= pointer)
.checked_sub(1)?;
let (offset, code_point_offset) = GB18030_RANGES[i];
Some(code_point_offset + (pointer - offset))
}
#[cfg(feature = "gb18030")]
pub(crate) fn gb18030_ranges_pointer(scalar: u32) -> Option<u32> {
if scalar == 0xE7C7 {
return Some(7457);
}
let i = GB18030_RANGES
.partition_point(|&(_, c)| c <= scalar)
.checked_sub(1)?;
let (offset, code_point_offset) = GB18030_RANGES[i];
Some(offset + (scalar - code_point_offset))
}
#[cfg(test)]
mod tests {
#[allow(unused_imports)]
use super::*;
#[cfg(feature = "gb18030")]
#[test]
fn ranges_round_trip() {
for &pointer in &[0u32, 7457, 39419, 189_000, 1_237_575] {
let cp = gb18030_ranges_code_point(pointer).expect("mapped pointer");
assert_eq!(
gb18030_ranges_pointer(cp),
Some(pointer),
"pointer {pointer}"
);
}
assert_eq!(gb18030_ranges_code_point(7457), Some(0xE7C7));
assert_eq!(gb18030_ranges_code_point(39420), None);
assert_eq!(gb18030_ranges_code_point(1_237_576), None);
assert_eq!(gb18030_ranges_code_point(189_000), Some(0x10000));
assert_eq!(gb18030_ranges_pointer(0x10FFFF), Some(1_237_575));
}
#[cfg(any(
feature = "euc-jp",
feature = "euc-kr",
feature = "gb18030",
feature = "iso-2022-jp",
feature = "shift-jis"
))]
#[test]
fn sentinel_means_unmapped() {
assert_eq!(code_point(&[0, 0x41], 0), None);
assert_eq!(code_point(&[0, 0x41], 1), Some(0x41));
assert_eq!(code_point(&[0, 0x41], 2), None);
}
}