use tarrasque::{Extract, ExtractError, ExtractResult, Stream, View, extract};
use crate::error::{UNSUPPORTED};
const EXPERT: &[(u8, u16)] = &[
(32, 1), (33, 229), (34, 230), (36, 231), (37, 232), (38, 233), (39, 234),
(40, 235), (41, 236), (42, 237), (43, 238), (44, 13), (45, 14), (46, 15),
(47, 99), (48, 239), (49, 240), (50, 241), (51, 242), (52, 243), (53, 244),
(54, 245), (55, 246), (56, 247), (57, 248), (58, 27), (59, 28), (60, 249),
(61, 250), (62, 251), (63, 252), (65, 253), (66, 254), (67, 255), (68, 256),
(69, 257), (73, 258), (76, 259), (77, 260), (78, 261), (79, 262), (82, 263),
(83, 264), (84, 265), (86, 266), (87, 109), (88, 110), (89, 267), (90, 268),
(91, 269), (93, 270), (94, 271), (95, 272), (96, 273), (97, 274), (98, 275),
(99, 276), (100, 277), (101, 278), (102, 279), (103, 280), (104, 281),
(105, 282), (106, 283), (107, 284), (108, 285), (109, 286), (110, 287),
(111, 288), (112, 289), (113, 290), (114, 291), (115, 292), (116, 293),
(117, 294), (118, 295), (119, 296), (120, 297), (121, 298), (122, 299),
(123, 300), (124, 301), (125, 302), (126, 303), (161, 304), (162, 305),
(163, 306), (166, 307), (167, 308), (168, 309), (169, 310), (170, 311),
(172, 312), (175, 313), (178, 314), (179, 315), (182, 316), (183, 317),
(184, 318), (188, 158), (189, 155), (190, 163), (191, 319), (192, 320),
(193, 321), (194, 322), (195, 323), (196, 324), (197, 325), (200, 326),
(201, 150), (202, 164), (203, 169), (204, 327), (205, 328), (206, 329),
(207, 330), (208, 331), (209, 332), (210, 333), (211, 334), (212, 335),
(213, 336), (214, 337), (215, 338), (216, 339), (217, 340), (218, 341),
(219, 342), (220, 343), (221, 344), (222, 345), (223, 346), (224, 347),
(225, 348), (226, 349), (227, 350), (228, 351), (229, 352), (230, 353),
(231, 354), (232, 355), (233, 356), (234, 357), (235, 358), (236, 359),
(237, 360), (238, 361), (239, 362), (240, 363), (241, 364), (242, 365),
(243, 366), (244, 367), (245, 368), (246, 369), (247, 370), (248, 371),
(249, 372), (250, 373), (251, 374), (252, 375), (253, 376), (254, 377),
(255, 378),
];
const STANDARD: &[u8] = &[
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105,
106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
121, 122, 123, 124, 125, 126, 161, 162, 163, 164, 165, 166, 167, 168, 169,
170, 171, 172, 173, 174, 175, 177, 178, 179, 180, 182, 183, 184, 185, 186,
187, 188, 189, 191, 193, 194, 195, 196, 197, 198, 199, 200, 202, 203, 205,
206, 207, 208, 225, 227, 232, 233, 234, 235, 241, 245, 248, 249, 250, 251,
];
extract! {
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Format0<'s> {
pub num_codes: u8 = [],
pub codes: &'s [u8] = [num_codes as usize],
}
}
impl<'s> Format0<'s> {
#[inline]
pub fn find_id(&self, codepoint: u32) -> usize {
let code = self.codes.get(codepoint as usize).cloned();
code.map(|i| usize::from(i) + 1).unwrap_or(0)
}
}
extract! {
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Range[2] {
pub first: u8 = [],
pub num_codes: u8 = [],
}
}
extract! {
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Format1<'s> {
pub num_ranges: u8 = [],
pub ranges: View<'s, Range, ()> = [(num_ranges as usize, ())],
}
}
impl<'s> Format1<'s> {
#[inline]
pub fn find_id(&self, mut codepoint: u32) -> usize {
for range in self.ranges.iter() {
let num_codes = u32::from(range.num_codes);
if codepoint < num_codes {
return range.first as usize + codepoint as usize + 1;
}
codepoint -= num_codes + 1;
}
0
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Encodings<'s> {
Expert,
Format0(Format0<'s>),
Format1(Format1<'s>),
Standard,
}
impl<'s> Encodings<'s> {
#[inline]
pub fn find_id(&self, codepoint: u32) -> usize {
match self {
Encodings::Expert => if codepoint <= 255 {
let codepoint = codepoint as u8;
EXPERT.binary_search_by_key(&codepoint, |e| e.0)
.ok()
.map(|i| EXPERT[i].1 as usize)
.unwrap_or(0)
} else {
0
},
Encodings::Format0(encodings) => encodings.find_id(codepoint),
Encodings::Format1(encodings) => encodings.find_id(codepoint),
Encodings::Standard => if codepoint <= 251 {
let codepoint = codepoint as u8;
STANDARD.binary_search(&codepoint)
.ok()
.map(|i| i + 1)
.unwrap_or(0)
} else {
0
},
}
}
}
impl<'s> Extract<'s, i32> for Encodings<'s> {
#[inline]
fn extract(
stream: &mut Stream<'s>, encoding: i32
) -> ExtractResult<'s, Self> {
match encoding {
0 => Ok(Encodings::Standard),
1 => Ok(Encodings::Expert),
_ => match stream.extract::<u8, _>(())? {
0 => Ok(Encodings::Format0(stream.extract(())?)),
1 => Ok(Encodings::Format1(stream.extract(())?)),
_ => Err(ExtractError::Code(UNSUPPORTED)),
}
}
}
}