extern crate alloc;
use core::{mem, ptr};
use alloc::collections::TryReserveError;
use alloc::vec::Vec;
#[derive(Copy, Clone, PartialEq)]
pub enum EncodeOp {
Process,
Flush,
Finish,
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum EncodeStatus {
Continue,
NeedOutput,
Finished,
Error,
}
#[derive(Debug)]
pub struct Encode {
pub input_remain: usize,
pub output_remain: usize,
pub status: EncodeStatus,
}
pub struct Interface {
reset_fn: fn(ptr::NonNull<u8>, opts: [u8; 2]) -> Option<ptr::NonNull<u8>>,
encode_fn: unsafe fn(ptr::NonNull<u8>, *const u8, usize, *mut u8, usize, EncodeOp) -> Encode,
drop_fn: fn(ptr::NonNull<u8>),
}
impl Interface {
pub const fn new(reset_fn: fn(ptr::NonNull<u8>, opts: [u8; 2]) -> Option<ptr::NonNull<u8>>, encode_fn: unsafe fn(ptr::NonNull<u8>, *const u8, usize, *mut u8, usize, EncodeOp) -> Encode, drop_fn: fn(ptr::NonNull<u8>)) -> Self {
Self {
reset_fn,
encode_fn,
drop_fn,
}
}
#[inline(always)]
pub(crate) fn inner_encoder(&'static self, instance: ptr::NonNull<u8>, opts: [u8; 2]) -> Encoder {
Encoder {
instance,
interface: self,
opts,
}
}
#[inline(always)]
pub unsafe fn encoder(&'static self, state: ptr::NonNull<u8>, opts: [u8; 2]) -> Encoder {
self.inner_encoder(state, opts)
}
}
pub struct Encoder {
instance: ptr::NonNull<u8>,
interface: &'static Interface,
opts: [u8; 2],
}
const _: () = {
assert!(mem::size_of::<Encoder>() == mem::size_of::<usize>() * 3);
};
impl Encoder {
#[inline(always)]
pub unsafe fn raw_encode(&mut self, input: *const u8, input_len: usize, output: *mut u8, output_len: usize, op: EncodeOp) -> Encode {
(self.interface.encode_fn)(self.instance, input, input_len, output, output_len, op)
}
#[inline(always)]
pub fn encode_uninit(&mut self, input: &[u8], output: &mut [mem::MaybeUninit<u8>], op: EncodeOp) -> Encode {
let input_len = input.len();
let output_len = output.len();
unsafe {
self.raw_encode(input.as_ptr(), input_len, output.as_mut_ptr() as _, output_len, op)
}
}
#[inline(always)]
pub fn encode(&mut self, input: &[u8], output: &mut [u8], op: EncodeOp) -> Encode {
let input_len = input.len();
let output_len = output.len();
unsafe {
self.raw_encode(input.as_ptr(), input_len, output.as_mut_ptr() as _, output_len, op)
}
}
#[inline(always)]
pub fn encode_vec(&mut self, input: &[u8], output: &mut Vec<u8>, op: EncodeOp) -> Encode {
let spare_capacity = output.spare_capacity_mut();
let spare_capacity_len = spare_capacity.len();
let result = self.encode_uninit(input, spare_capacity, op);
let new_len = output.len() + spare_capacity_len - result.output_remain;
unsafe {
output.set_len(new_len);
}
result
}
#[inline(always)]
pub fn encode_vec_full(&mut self, mut input: &[u8], output: &mut Vec<u8>, op: EncodeOp) -> Result<Encode, TryReserveError> {
const RESERVE_DEFAULT: usize = 1024;
let input_len = input.len();
let reserve_size = if input_len < RESERVE_DEFAULT {
output.try_reserve_exact(input_len)?;
input_len / 3
} else if input_len < (RESERVE_DEFAULT * 16) {
output.try_reserve_exact(input_len / 2)?;
RESERVE_DEFAULT
} else {
output.try_reserve_exact(input.len() / 3)?;
RESERVE_DEFAULT * 8
};
loop {
let result = self.encode_vec(input, output, op);
match result.status {
EncodeStatus::NeedOutput => {
input = &input[input.len() - result.input_remain..];
output.try_reserve_exact(reserve_size)?;
continue;
}
EncodeStatus::Continue if op == EncodeOp::Finish => {
input = &input[input.len() - result.input_remain..];
continue;
}
_ => break Ok(result),
}
}
}
#[cfg(feature = "bytes")]
pub fn encode_buf(&mut self, mut input: &[u8], output: &mut impl bytes::BufMut, op: EncodeOp) -> Encode {
let mut result = Encode {
input_remain: input.len(),
output_remain: output.remaining_mut(),
status: EncodeStatus::NeedOutput,
};
loop {
let spare_capacity = output.chunk_mut();
let spare_capacity_len = spare_capacity.len();
let (advanced_len, encode) = unsafe {
let encode = self.encode_uninit(input, spare_capacity.as_uninit_slice_mut(), op);
debug_assert!(spare_capacity_len > encode.output_remain);
let advanced_len = spare_capacity_len.saturating_sub(encode.output_remain);
output.advance_mut(advanced_len);
(advanced_len, encode)
};
input = &input[result.input_remain - encode.input_remain..];
result.input_remain = encode.input_remain;
result.output_remain = result.output_remain.saturating_sub(advanced_len);
result.status = encode.status;
match result.status {
EncodeStatus::Error | EncodeStatus::Finished | EncodeStatus::Continue => break result,
EncodeStatus::NeedOutput => {
if result.output_remain == 0 {
break result;
}
}
}
}
}
#[inline(always)]
pub fn reset(&mut self) -> bool {
match (self.interface.reset_fn)(self.instance, self.opts) {
Some(ptr) => {
self.instance = ptr;
true
}
None => false,
}
}
}
impl Drop for Encoder {
#[inline]
fn drop(&mut self) {
(self.interface.drop_fn)(self.instance);
}
}
#[cfg(any(feature = "zlib", feature = "zlib-static", feature = "zlib-ng", feature = "zlib-rust"))]
macro_rules! internal_zlib_impl_encode {
($state:ident, $input:ident, $input_remain:ident, $output:ident, $output_remain:ident, $op:ident) => {{
let op = match $op {
$crate::encoder::EncodeOp::Process => sys::Z_NO_FLUSH,
$crate::encoder::EncodeOp::Flush => sys::Z_SYNC_FLUSH,
$crate::encoder::EncodeOp::Finish => sys::Z_FINISH
};
let state = unsafe {
&mut *($state.as_ptr() as *mut State)
};
state.inner.avail_out = $output_remain as _;
state.inner.next_out = $output;
state.inner.avail_in = $input_remain as _;
state.inner.next_in = $input as *mut _;
let result = sys::deflate(state.as_mut(), op);
$crate::encoder::Encode {
input_remain: state.inner.avail_in as usize,
output_remain: state.inner.avail_out as usize,
status: match result {
sys::Z_STREAM_END => $crate::encoder::EncodeStatus::Finished,
sys::Z_OK => if op == sys::Z_FINISH {
$crate::encoder::EncodeStatus::NeedOutput
} else {
$crate::encoder::EncodeStatus::Continue
},
sys::Z_BUF_ERROR => $crate::encoder::EncodeStatus::NeedOutput,
_ => $crate::encoder::EncodeStatus::Error,
}
}
}}
}
#[cfg(any(feature = "brotli", feature = "brotli-c"))]
mod brotli_common;
#[cfg(any(feature = "brotli", feature = "brotli-c"))]
pub use brotli_common::{BrotliEncoderMode, BrotliOptions};
#[cfg(feature = "brotli")]
mod brotli;
#[cfg(feature = "brotli-c")]
mod brotli_c;
#[cfg(any(feature = "zlib", feature = "zlib-static", feature = "zlib-ng", feature = "zlib-rs"))]
mod zlib_common;
#[cfg(any(feature = "zlib", feature = "zlib-static", feature = "zlib-ng", feature = "zlib-rs"))]
pub use zlib_common::*;
#[cfg(any(feature = "zlib", feature = "zlib-static"))]
mod zlib;
#[cfg(feature = "zlib-ng")]
mod zlib_ng;
#[cfg(feature = "zlib-rust")]
mod zlib_rust;
#[cfg(feature = "zstd")]
mod zstd;
#[cfg(feature = "zstd")]
pub use zstd::{ZstdOptions, ZstdStrategy};
impl<const N: usize> crate::Buffer<N> {
pub fn encode(&mut self, encoder: &mut Encoder, input: &[u8], op: EncodeOp) -> (usize, EncodeStatus) {
let spare_capacity = self.spare_capacity_mut();
let spare_capacity_len = spare_capacity.len();
let result = encoder.encode_uninit(input, spare_capacity, op);
self.cursor = self.cursor + spare_capacity_len - result.output_remain;
(input.len() - result.input_remain, result.status)
}
}