use crate::bit_reader::BitReader;
use crate::state_machine::{
BLACK_STATES, INVALID, MODE_STATES, State, TERMINAL, VALUE_MASK, WHITE_STATES,
};
use crate::{Color, DecodeError, Result};
pub(crate) const EOFB: u32 = 0x1001;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum Mode {
Pass,
Horizontal,
Vertical(i8),
}
impl BitReader<'_> {
#[inline(always)]
fn decode_run_inner(&mut self, states: &[State]) -> Result<u32> {
let mut total: u32 = 0;
let mut state: usize = 0;
loop {
let bit = self.read_bit()?;
let transition = if bit == 0 {
states[state].on_0
} else {
states[state].on_1
};
if transition == INVALID {
return Err(DecodeError::InvalidCode);
} else if transition & TERMINAL != 0 {
let len = (transition & VALUE_MASK) as u32;
total = total.checked_add(len).ok_or(DecodeError::Overflow)?;
if len < 64 {
return Ok(total);
}
state = 0;
} else {
state = transition as usize;
}
}
}
#[inline(always)]
fn decode_white_run(&mut self) -> Result<u32> {
let saved = self.clone();
self.decode_run_inner(&WHITE_STATES).or_else(|_| {
*self = saved;
self.decode_run_inner(&BLACK_STATES)
})
}
#[inline(always)]
fn decode_black_run(&mut self) -> Result<u32> {
let saved = self.clone();
self.decode_run_inner(&BLACK_STATES).or_else(|_| {
*self = saved;
self.decode_run_inner(&WHITE_STATES)
})
}
#[inline(always)]
pub(crate) fn decode_run(&mut self, color: Color) -> Result<u32> {
match color {
Color::White => self.decode_white_run(),
Color::Black => self.decode_black_run(),
}
}
#[inline(always)]
pub(crate) fn decode_mode(&mut self) -> Result<Mode> {
let mode_value = self.decode_run_inner(&MODE_STATES)?;
Ok(match mode_value {
0 => Mode::Pass,
1 => Mode::Horizontal,
2 => Mode::Vertical(0),
3 => Mode::Vertical(1),
4 => Mode::Vertical(2),
5 => Mode::Vertical(3),
6 => Mode::Vertical(-1),
7 => Mode::Vertical(-2),
8 => Mode::Vertical(-3),
_ => return Err(DecodeError::InvalidCode),
})
}
#[inline(always)]
pub(crate) fn read_eol_if_available(&mut self) -> usize {
let mut count = 0;
loop {
let mut fill_bits = 0;
const MAX_FILL_BITS: usize = 24;
while fill_bits < MAX_FILL_BITS {
match self.peak_bits(fill_bits + 1) {
Ok(0) => fill_bits += 1,
_ => break,
}
}
if fill_bits >= 11 && self.peak_bits(fill_bits + 1) == Ok(1) {
self.read_bits(fill_bits + 1).unwrap();
count += 1;
continue;
}
return count;
}
}
}