use crate::block::types::{
wild_copy8, write_le16, LimitedOutputDirective, LASTLITERALS, LZ4_DISTANCE_MAX, MINMATCH,
ML_BITS, ML_MASK, RUN_MASK,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Lz4HcError {
OutputTooSmall,
}
#[inline(always)]
pub unsafe fn encode_sequence(
ip: &mut *const u8,
op: &mut *mut u8,
anchor: &mut *const u8,
match_length: i32,
offset: i32,
limit: LimitedOutputDirective,
oend: *mut u8,
) -> Result<(), Lz4HcError> {
let literal_length: usize = (*ip).offset_from(*anchor) as usize;
let token: *mut u8 = *op;
*op = (*op).add(1);
if limit == LimitedOutputDirective::LimitedOutput {
let needed = literal_length / 255 + literal_length + (2 + 1 + LASTLITERALS);
if (*op).add(needed) > oend {
return Err(Lz4HcError::OutputTooSmall);
}
}
if literal_length >= RUN_MASK as usize {
*token = (RUN_MASK << ML_BITS) as u8;
let mut remaining = literal_length - RUN_MASK as usize;
while remaining >= 255 {
**op = 255u8;
*op = (*op).add(1);
remaining -= 255;
}
**op = remaining as u8;
*op = (*op).add(1);
} else {
*token = (literal_length << ML_BITS as usize) as u8;
}
wild_copy8(*op, *anchor, (*op).add(literal_length));
*op = (*op).add(literal_length);
debug_assert!(offset > 0);
debug_assert!(offset <= LZ4_DISTANCE_MAX as i32);
write_le16(*op, offset as u16);
*op = (*op).add(2);
debug_assert!(match_length >= MINMATCH as i32);
let mut ml_remaining = (match_length as usize) - MINMATCH;
if limit == LimitedOutputDirective::LimitedOutput {
let needed = ml_remaining / 255 + (1 + LASTLITERALS);
if (*op).add(needed) > oend {
return Err(Lz4HcError::OutputTooSmall);
}
}
if ml_remaining >= ML_MASK as usize {
*token += ML_MASK as u8;
ml_remaining -= ML_MASK as usize;
while ml_remaining >= 510 {
**op = 255u8;
*(*op).add(1) = 255u8;
*op = (*op).add(2);
ml_remaining -= 510;
}
if ml_remaining >= 255 {
**op = 255u8;
*op = (*op).add(1);
ml_remaining -= 255;
}
**op = ml_remaining as u8;
*op = (*op).add(1);
} else {
*token += ml_remaining as u8;
}
*ip = (*ip).add(match_length as usize);
*anchor = *ip;
Ok(())
}