use super::brotli_common::BrotliOptions;
use super::{Encode, EncodeOp, EncodeStatus, Encoder, Interface};
use crate::mem::brotli_rust::BrotliAllocator;
use crate::mem::Box;
use core::{ptr, slice};
pub(crate) type Instance = brotli::enc::encode::BrotliEncoderStateStruct<BrotliAllocator>;
static BROTLI_RUST: Interface = Interface::new(
reset_fn,
encode_fn,
drop_fn
);
impl Interface {
#[inline]
pub fn brotli_rust(options: BrotliOptions) -> Encoder {
let mut state = Box::new(instance());
options.apply_rust(&mut state);
let ptr = ptr::NonNull::from(Box::leak(state));
BROTLI_RUST.inner_encoder(ptr.cast(), options.inner)
}
}
impl EncodeOp {
#[inline(always)]
const fn into_rust_brotli(self) -> brotli::enc::encode::BrotliEncoderOperation {
match self {
Self::Process => brotli::enc::encode::BrotliEncoderOperation::BROTLI_OPERATION_PROCESS,
Self::Flush => brotli::enc::encode::BrotliEncoderOperation::BROTLI_OPERATION_FLUSH,
Self::Finish => brotli::enc::encode::BrotliEncoderOperation::BROTLI_OPERATION_FINISH,
}
}
}
fn instance() -> Instance {
Instance::new(Default::default())
}
unsafe fn encode_fn(state: ptr::NonNull<u8>, input: *const u8, mut input_remain: usize, output: *mut u8, mut output_remain: usize, op: EncodeOp) -> Encode {
let state = unsafe {
&mut *(state.as_ptr() as *mut Instance)
};
let input = unsafe {
slice::from_raw_parts(input, input_remain)
};
let output = unsafe {
slice::from_raw_parts_mut(output, output_remain)
};
let result = state.compress_stream(op.into_rust_brotli(), &mut input_remain,
input, &mut 0,
&mut output_remain, output,
&mut 0, &mut None,
&mut |_a, _b, _c, _d| ()
);
let has_more_output = state.has_more_output();
Encode {
input_remain,
output_remain,
status: match result {
false => match has_more_output {
false => EncodeStatus::Error,
true => EncodeStatus::NeedOutput,
},
true => {
if has_more_output {
EncodeStatus::NeedOutput
} else if op == EncodeOp::Finish {
EncodeStatus::Finished
} else {
EncodeStatus::Continue
}
}
},
}
}
#[inline]
fn reset_fn(state: ptr::NonNull<u8>, opts: [u8; 2]) -> Option<ptr::NonNull<u8>> {
let options = BrotliOptions::from_raw(opts);
let mut state = unsafe { Box::from_raw(state.as_ptr() as *mut Instance) };
*state = instance();
options.apply_rust(&mut state);
let ptr = Box::leak(state);
Some(ptr::NonNull::from(ptr).cast())
}
#[inline]
fn drop_fn(state: ptr::NonNull<u8>) {
let _ = unsafe {
Box::from_raw(state.as_ptr() as *mut Instance)
};
}