use crate::compressor::lz;
use libc::c_int;
use std::cmp;
use std::ffi::c_void;
use std::mem::MaybeUninit;
use std::ptr::NonNull;
pub type Lzvn = lz::Lz<Impl>;
pub enum Impl {}
unsafe impl lz::Impl for Impl {
const UNCOMPRESSED_PREFIX: Option<u8> = Some(0x06);
fn scratch_size() -> usize {
const {
assert!(align_of::<DecoderState>() <= align_of::<*mut u8>());
}
lz::cached_size!(cmp::max(
size_of::<DecoderState>(),
unsafe { lzvn_encode_scratch_size() },
))
}
unsafe fn encode(dst: &mut [u8], src: &[u8], scratch: NonNull<u8>) -> usize {
let res = unsafe {
lzvn_encode_buffer(
dst.as_mut_ptr(),
dst.len(),
src.as_ptr(),
src.len(),
scratch.as_ptr().cast(),
)
};
debug_assert!(res <= dst.len());
res
}
#[no_mangle]
unsafe fn decode(dst: &mut [u8], src: &[u8], scratch: NonNull<u8>) -> usize {
const _: () = {
assert!(align_of::<DecoderState>() <= align_of::<*mut u8>());
};
let state = unsafe { scratch.cast::<MaybeUninit<DecoderState>>().as_mut() };
let state: &mut DecoderState = state.write(DecoderState::default());
let src_range = src.as_ptr_range();
state.src = src_range.start;
state.src_end = src_range.end;
let dst_range = dst.as_mut_ptr_range();
state.dst = dst_range.start;
state.dst_begin = dst_range.start;
state.dst_end = dst_range.end;
unsafe {
lzvn_decode(state);
}
assert!(dst_range.contains(&state.dst));
unsafe { state.dst.offset_from_unsigned(dst.as_mut_ptr()) }
}
}
const _: () = {
let _ = lzfse_sys::lzfse_encode_buffer;
};
#[repr(C)]
#[derive(Default)]
struct DecoderState {
src: *const u8,
src_end: *const u8,
dst: *mut u8,
dst_begin: *mut u8,
dst_end: *mut u8,
dst_current: *mut u8,
l: usize,
m: usize,
d: usize,
d_prev: isize,
end_of_stream: c_int,
}
extern "C" {
fn lzvn_encode_scratch_size() -> usize;
fn lzvn_encode_buffer(
dst: *mut u8,
dst_size: usize,
src: *const u8,
src_size: usize,
work: *mut c_void,
) -> usize;
fn lzvn_decode(state: *mut DecoderState);
}
#[test]
fn round_trip() {
let mut compressor = Lzvn::new();
super::tests::compressor_round_trip(&mut compressor);
}