const N_LEAD_BYTES_1: i32 = 64;
const N_LEAD_BYTES_2: i32 = 43;
const N_LEAD_BYTES_3: i32 = 3;
const LO_1BYTE_DELTA: i32 = -N_LEAD_BYTES_1;
const HI_1BYTE_DELTA: i32 = N_LEAD_BYTES_1 - 1;
const_assert_eq!(assert_L1D; LO_1BYTE_DELTA, -0x0000_0040);
const_assert_eq!(assert_H1D; HI_1BYTE_DELTA, 0x0000_003F);
const RANGE_2BYTE: i32 = N_LEAD_BYTES_2 * N_TRAIL_VALUES;
const LO_2BYTE_DELTA: i32 = LO_1BYTE_DELTA - RANGE_2BYTE;
const HI_2BYTE_DELTA: i32 = HI_1BYTE_DELTA + RANGE_2BYTE;
const_assert_eq!(assert_L2D; LO_2BYTE_DELTA, -0x0000_2911);
const_assert_eq!(assert_H2D; HI_2BYTE_DELTA, 0x0000_2910);
const RANGE_3BYTE: i32 = N_LEAD_BYTES_3 * N_TRAIL_VALUES * N_TRAIL_VALUES;
const LO_3BYTE_DELTA: i32 = LO_2BYTE_DELTA - RANGE_3BYTE;
const HI_3BYTE_DELTA: i32 = HI_2BYTE_DELTA + RANGE_3BYTE;
const_assert_eq!(assert_L3D; LO_3BYTE_DELTA, -0x0002_DD0C);
const_assert_eq!(assert_H3D; HI_3BYTE_DELTA, 0x0002_DD0B);
use crate::trailing_byte_selection;
use crate::trailing_byte_selection::N_TRAIL_VALUES;
use crate::util::Euc;
use crate::{DecodeError, EncodedChunk};
#[inline]
#[allow(clippy::cast_sign_loss)]
#[allow(clippy::cast_possible_truncation)]
pub fn encode_delta(delta: i32) -> EncodedChunk {
let (offset, lead, len): (i32, u8, usize) = match delta {
-0x0010_FF9F..=-0x0002_DD0D => (-0x0002_DD0C, 0x22, 4),
-0x0002_DD0C..=-0x0000_2912 => (-0x0000_2911, 0x25, 3),
-0x0000_2911..=-0x0000_0041 => (-0x0000_0040, 0x50, 2),
-0x0000_0040..=0x0000_003F => (0x0000_0000, 0x90, 1),
0x0000_0040..=0x0000_2910 => (0x0000_0040, 0xD0, 2),
0x0000_2911..=0x0002_DD0B => (0x0000_2911, 0xFB, 3),
0x0002_DD0C..=0x0010_FFBF => (0x0002_DD0C, 0xFE, 4),
_ => panic!("bug in VariableLengthCode::encode_delta"),
};
trace!(
"VariableLengthCode: delta {} (= 0x{:x}) gets \
{}-value code, lead byte 0x{:x}",
delta,
delta,
len,
lead
);
let mut buf: [u8; 4] = [lead, 0x0, 0x0, 0x0];
let mut d: i32 = delta - offset;
let divisor: i32 = N_TRAIL_VALUES;
for i in (1..len).rev() {
let m: i32 = Euc::mod_euc(d, divisor);
d = Euc::div_euc(d, divisor);
trace!(
"VariableLengthCode: byte {}: adding trail \
modulus {} to buffer value 0x{:x}",
i,
m,
buf[i]
);
assert!(0 <= m && m <= 0xff);
buf[i] = trailing_byte_selection::trail_to_byte(m as u8);
}
trace!(
"VariableLengthCode: byte 0: adding lead \
divisor {} to buffer lead-byte 0x{:x}",
d,
buf[0]
);
let init: i32 = i32::from(buf[0]) + d;
assert!(0 < init && init <= 0xff);
buf[0] = init as u8;
trace!(
"VariableLengthCode: final code for delta {} is {:?}",
delta,
&buf[0..len]
);
EncodedChunk {
bytes: buf,
count: len,
}
}
pub const LEAD_BYTE_RESET: u8 = 0xff;
pub const LEAD_BYTE_ASCII_SP: u8 = 0x20;
#[inline]
#[allow(clippy::needless_range_loop)] pub fn decode_delta(b: &[u8]) -> Result<(i32, &[u8]), DecodeError> {
assert!(!b.is_empty());
let lead: u8 = b[0];
assert!(lead > LEAD_BYTE_ASCII_SP);
assert!(lead != LEAD_BYTE_RESET);
let (offset, base, len): (i32, u8, usize) = match lead {
| 0x21 ..= 0x21 /* 1 code */ => (-0x0002_DD0C, 0x22, 4),
| 0x22 ..= 0x24 => (-0x0000_2911, 0x25, 3),
| 0x25 ..= 0x4F /* 43 codes */ => (-0x0000_0040, 0x50, 2),
| 0x50 ..= 0xCF => ( 0x0000_0000, 0x90, 1),
| 0xD0 ..= 0xFA /* 43 codes */ => ( 0x0000_0040, 0xD0, 2),
| 0xFB ..= 0xFD => ( 0x0000_2911, 0xFB, 3),
| 0xFE ..= 0xFE /* 1 code */ => ( 0x0002_DD0C, 0xFE, 4),
| _ => panic!("bug in VariableLengthCode::decode_delta")
};
if b.len() < len {
return Err(DecodeError::TruncatedInput);
}
let mut delta: i32 = i32::from(lead) - i32::from(base);
for i in 1..len {
delta *= N_TRAIL_VALUES;
delta += i32::from(trailing_byte_selection::byte_to_trail(b[i])?);
}
delta += offset;
Ok((delta, &b[len..]))
}