use crate::*;
pub fn normalized_prev(curr: char) -> char {
match curr {
'\u{3040}'..='\u{309F}' => '\u{3070}',
'\u{4E00}'..='\u{9FA5}' => '\u{7711}',
'\u{AC00}'..='\u{D7A3}' => '\u{C1D1}',
_ => {
let cu32 = curr as u32;
let guess_curr_block_start = cu32 & 0xffff_ff80_u32;
let guess_curr_block_middle = guess_curr_block_start + 0x40;
let opt = ::std::char::from_u32(guess_curr_block_middle);
opt.expect("bug in BOCU1Encoder::normalized_prev")
}
}
}
pub struct DeltaCoder {
prev: char,
}
const INITIAL_PREVIOUS_STATE: char = '\u{40}';
const ASCII_SP: char = '\u{20}';
#[allow(clippy::new_without_default_derive)]
impl DeltaCoder {
pub fn new() -> Self {
Self {
prev: INITIAL_PREVIOUS_STATE,
}
}
#[inline]
pub fn encode_char(self: &mut Self, curr: char) -> EncodedChunk {
trace!("DeltaCoder: char 0x{:x}", curr as u32);
if curr <= ASCII_SP {
if curr != ASCII_SP {
trace!("DeltaCoder: reset prev to 0x40");
self.prev = INITIAL_PREVIOUS_STATE;
}
trace!("DeltaCoder: self-encoding 0x{:x}", curr as u32);
EncodedChunk::new_single(curr as u8)
} else {
let delta: i32 = (curr as i32) - (self.prev as i32);
self.prev = normalized_prev(curr);
trace!("DeltaCoder: set prev to 0x{:x}", self.prev as u32);
trace!("DeltaCoder: encoding delta {}", delta);
variable_length_code::encode_delta(delta)
}
}
#[allow(clippy::cast_sign_loss)]
pub fn decode_char<'a>(
self: &mut Self,
b: &'a [u8],
) -> Result<(Option<char>, &'a [u8]), DecodeError> {
assert!(!b.is_empty());
let init = b[0];
if init == variable_length_code::LEAD_BYTE_RESET {
Ok((None, &b[1..]))
} else if init <= variable_length_code::LEAD_BYTE_ASCII_SP {
if init != variable_length_code::LEAD_BYTE_ASCII_SP {
self.prev = INITIAL_PREVIOUS_STATE;
}
Ok((Some(init as char), &b[1..]))
} else {
let (delta, rest) = variable_length_code::decode_delta(b)?;
let candidate = (self.prev as i32) + delta;
let c = ::std::char::from_u32(candidate as u32);
match c {
None => Err(DecodeError::CharDeltaOutOfRange(self.prev, delta)),
Some(ch) => {
self.prev = normalized_prev(ch);
Ok((Some(ch), rest))
}
}
}
}
}