use std::error::Error;
use std::fmt;
use std::ptr::NonNull;
use libdeflate_sys::{libdeflate_decompressor,
libdeflate_free_decompressor,
libdeflate_gzip_decompress,
libdeflate_zlib_decompress,
libdeflate_deflate_decompress,
libdeflate_result,
libdeflate_result_LIBDEFLATE_SUCCESS,
libdeflate_result_LIBDEFLATE_BAD_DATA,
libdeflate_result_LIBDEFLATE_INSUFFICIENT_SPACE,
libdeflate_compressor,
libdeflate_deflate_compress_bound,
libdeflate_deflate_compress,
libdeflate_zlib_compress_bound,
libdeflate_zlib_compress,
libdeflate_gzip_compress_bound,
libdeflate_gzip_compress,
libdeflate_free_compressor,
libdeflate_crc32,
libdeflate_adler32};
#[cfg(feature = "use_rust_alloc")]
mod malloc_wrapper;
unsafe fn alloc_compressor(compression_level: std::os::raw::c_int) -> *mut libdeflate_compressor {
#[cfg(feature = "use_rust_alloc")]
{ libdeflate_sys::libdeflate_alloc_compressor_ex(compression_level, &malloc_wrapper::OPTIONS) }
#[cfg(not(feature = "use_rust_alloc"))]
{ libdeflate_sys::libdeflate_alloc_compressor(compression_level) }
}
unsafe fn alloc_decompressor() -> *mut libdeflate_decompressor {
#[cfg(feature = "use_rust_alloc")]
{ libdeflate_sys::libdeflate_alloc_decompressor_ex(&malloc_wrapper::OPTIONS) }
#[cfg(not(feature = "use_rust_alloc"))]
{ libdeflate_sys::libdeflate_alloc_decompressor() }
}
pub struct Decompressor {
p: NonNull<libdeflate_decompressor>,
}
unsafe impl Send for Decompressor {}
unsafe impl Sync for Decompressor {}
#[derive(Debug, PartialEq)]
pub enum DecompressionError {
BadData,
InsufficientSpace,
}
impl fmt::Display for DecompressionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self {
DecompressionError::BadData => write!(f, "the data provided to a libdeflater *_decompress function call was invalid in some way (e.g. bad magic numbers, bad checksum)"),
DecompressionError::InsufficientSpace => write!(f, "a buffer provided to a libdeflater *_decompress function call was too small to accommodate the decompressed data")
}
}
}
impl Error for DecompressionError {}
type DecompressionResult<T> = std::result::Result<T, DecompressionError>;
impl Default for Decompressor {
fn default() -> Self {
Self::new()
}
}
#[allow(non_upper_case_globals)]
impl Decompressor {
pub fn new() -> Decompressor {
unsafe {
let ptr = alloc_decompressor();
if let Some(ptr) = NonNull::new(ptr) {
Decompressor{ p: ptr }
} else {
panic!("libdeflate_alloc_decompressor returned NULL: out of memory");
}
}
}
pub fn gzip_decompress(&mut self,
gz_data: &[u8],
out: &mut [u8]) -> DecompressionResult<usize> {
unsafe {
let mut out_nbytes = 0;
let in_ptr = gz_data.as_ptr() as *const std::ffi::c_void;
let out_ptr = out.as_mut_ptr() as *mut std::ffi::c_void;
let ret: libdeflate_result =
libdeflate_gzip_decompress(self.p.as_ptr(),
in_ptr,
gz_data.len(),
out_ptr,
out.len(),
&mut out_nbytes);
match ret {
libdeflate_result_LIBDEFLATE_SUCCESS => {
Ok(out_nbytes)
},
libdeflate_result_LIBDEFLATE_BAD_DATA => {
Err(DecompressionError::BadData)
},
libdeflate_result_LIBDEFLATE_INSUFFICIENT_SPACE => {
Err(DecompressionError::InsufficientSpace)
},
_ => {
panic!("libdeflate_gzip_decompress returned an unknown error type: this is an internal bug that **must** be fixed");
}
}
}
}
pub fn zlib_decompress(&mut self,
zlib_data: &[u8],
out: &mut [u8]) -> DecompressionResult<usize> {
unsafe {
let mut out_nbytes = 0;
let in_ptr = zlib_data.as_ptr() as *const std::ffi::c_void;
let out_ptr = out.as_mut_ptr() as *mut std::ffi::c_void;
let ret: libdeflate_result =
libdeflate_zlib_decompress(self.p.as_ptr(),
in_ptr,
zlib_data.len(),
out_ptr,
out.len(),
&mut out_nbytes);
match ret {
libdeflate_result_LIBDEFLATE_SUCCESS => {
Ok(out_nbytes)
},
libdeflate_result_LIBDEFLATE_BAD_DATA => {
Err(DecompressionError::BadData)
},
libdeflate_result_LIBDEFLATE_INSUFFICIENT_SPACE => {
Err(DecompressionError::InsufficientSpace)
},
_ => {
panic!("libdeflate_zlib_decompress returned an unknown error type: this is an internal bug that **must** be fixed");
}
}
}
}
pub fn deflate_decompress(&mut self,
deflate_data: &[u8],
out: &mut [u8]) -> DecompressionResult<usize> {
unsafe {
let mut out_nbytes = 0;
let in_ptr = deflate_data.as_ptr() as *const std::ffi::c_void;
let out_ptr = out.as_mut_ptr() as *mut std::ffi::c_void;
let ret: libdeflate_result =
libdeflate_deflate_decompress(self.p.as_ptr(),
in_ptr,
deflate_data.len(),
out_ptr,
out.len(),
&mut out_nbytes);
match ret {
libdeflate_result_LIBDEFLATE_SUCCESS => {
Ok(out_nbytes)
},
libdeflate_result_LIBDEFLATE_BAD_DATA => {
Err(DecompressionError::BadData)
},
libdeflate_result_LIBDEFLATE_INSUFFICIENT_SPACE => {
Err(DecompressionError::InsufficientSpace)
},
_ => {
panic!("libdeflate_deflate_decompress returned an unknown error type: this is an internal bug that **must** be fixed");
}
}
}
}
}
impl Drop for Decompressor {
fn drop(&mut self) {
unsafe {
libdeflate_free_decompressor(self.p.as_ptr());
}
}
}
const MIN_COMPRESSION_LVL: i32 = 0;
const DEFAULT_COMPRESSION_LVL : i32 = 6;
const MAX_COMPRESSION_LVL: i32 = 12;
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct CompressionLvl(i32);
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum CompressionLvlError {
InvalidValue,
}
type CompressionLevelResult = Result<CompressionLvl, CompressionLvlError>;
impl CompressionLvl {
pub const fn new(level: i32) -> CompressionLevelResult {
if MIN_COMPRESSION_LVL <= level && level <= MAX_COMPRESSION_LVL {
Ok(CompressionLvl(level))
} else {
Err(CompressionLvlError::InvalidValue)
}
}
pub const fn fastest() -> CompressionLvl {
CompressionLvl(MIN_COMPRESSION_LVL)
}
pub const fn best() -> CompressionLvl {
CompressionLvl(MAX_COMPRESSION_LVL)
}
pub const fn iter() -> CompressionLvlIter {
CompressionLvlIter(MIN_COMPRESSION_LVL)
}
}
impl Default for CompressionLvl {
fn default() -> CompressionLvl {
CompressionLvl(DEFAULT_COMPRESSION_LVL)
}
}
pub struct CompressionLvlIter(i32);
impl Iterator for CompressionLvlIter {
type Item = CompressionLvl;
fn next(&mut self) -> Option<Self::Item> {
if self.0 <= MAX_COMPRESSION_LVL {
let ret = Some(CompressionLvl(self.0));
self.0 += 1;
ret
} else {
None
}
}
}
impl From<CompressionLvl> for i32 {
fn from(level: CompressionLvl) -> Self {
level.0
}
}
impl From<&CompressionLvl> for i32 {
fn from(level: &CompressionLvl) -> Self {
level.0
}
}
#[derive(Debug, PartialEq)]
pub enum CompressionError {
InsufficientSpace,
}
impl fmt::Display for CompressionError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self {
CompressionError::InsufficientSpace => write!(f, "the output buffer provided to a libdeflater *_compress function call was too small for the input data"),
}
}
}
impl Error for CompressionError {}
type CompressionResult<T> = std::result::Result<T, CompressionError>;
pub struct Compressor {
p: NonNull<libdeflate_compressor>,
}
unsafe impl Send for Compressor {}
unsafe impl Sync for Compressor {}
impl Default for Compressor {
fn default() -> Self {
Self::new(CompressionLvl::default())
}
}
impl Compressor {
pub fn new(lvl: CompressionLvl) -> Compressor {
unsafe {
let ptr = alloc_compressor(lvl.0 as _);
if let Some(ptr) = NonNull::new(ptr) {
Compressor{ p: ptr }
} else {
panic!("libdeflate_alloc_compressor returned NULL: out of memory");
}
}
}
pub fn deflate_compress_bound(&mut self, n_bytes: usize) -> usize {
unsafe {
libdeflate_deflate_compress_bound(self.p.as_ptr(), n_bytes)
}
}
pub fn deflate_compress(&mut self,
in_raw_data: &[u8],
out_deflate_data: &mut [u8]) -> CompressionResult<usize> {
unsafe {
let in_ptr = in_raw_data.as_ptr() as *const std::ffi::c_void;
let out_ptr = out_deflate_data.as_mut_ptr() as *mut std::ffi::c_void;
let sz = libdeflate_deflate_compress(self.p.as_ptr(),
in_ptr,
in_raw_data.len(),
out_ptr,
out_deflate_data.len());
if sz != 0 {
Ok(sz)
} else {
Err(CompressionError::InsufficientSpace)
}
}
}
pub fn zlib_compress_bound(&mut self, n_bytes: usize) -> usize {
unsafe {
libdeflate_zlib_compress_bound(self.p.as_ptr(), n_bytes)
}
}
pub fn zlib_compress(&mut self,
in_raw_data: &[u8],
out_zlib_data: &mut [u8]) -> CompressionResult<usize> {
unsafe {
let in_ptr = in_raw_data.as_ptr() as *const std::ffi::c_void;
let out_ptr = out_zlib_data.as_mut_ptr() as *mut std::ffi::c_void;
let sz = libdeflate_zlib_compress(self.p.as_ptr(),
in_ptr,
in_raw_data.len(),
out_ptr,
out_zlib_data.len());
if sz != 0 {
Ok(sz)
} else {
Err(CompressionError::InsufficientSpace)
}
}
}
pub fn gzip_compress_bound(&mut self, n_bytes: usize) -> usize {
unsafe {
libdeflate_gzip_compress_bound(self.p.as_ptr(), n_bytes)
}
}
pub fn gzip_compress(&mut self,
in_raw_data: &[u8],
out_gzip_data: &mut [u8]) -> CompressionResult<usize> {
unsafe {
let in_ptr = in_raw_data.as_ptr() as *const std::ffi::c_void;
let out_ptr = out_gzip_data.as_mut_ptr() as *mut std::ffi::c_void;
let sz = libdeflate_gzip_compress(self.p.as_ptr(),
in_ptr,
in_raw_data.len(),
out_ptr,
out_gzip_data.len());
if sz != 0 {
Ok(sz)
} else {
Err(CompressionError::InsufficientSpace)
}
}
}
}
impl Drop for Compressor {
fn drop(&mut self) {
unsafe {
libdeflate_free_compressor(self.p.as_ptr());
}
}
}
pub struct Crc {
val: u32,
}
impl Default for Crc {
fn default() -> Self {
Self::new()
}
}
impl Crc {
pub const fn new() -> Crc {
Crc { val: 0 }
}
pub const fn with_initial(val: u32) -> Crc {
Crc { val }
}
pub fn update(&mut self, data: &[u8]) {
unsafe {
self.val = libdeflate_crc32(self.val,
data.as_ptr() as *const core::ffi::c_void,
data.len());
}
}
pub const fn sum(&self) -> u32 {
self.val
}
}
pub fn crc32(data: &[u8]) -> u32 {
let mut crc = Crc::new();
crc.update(&data);
crc.sum()
}
pub struct Adler32 {
val: u32,
}
impl Default for Adler32 {
fn default() -> Self {
Self::new()
}
}
impl Adler32 {
pub const fn new() -> Adler32 {
Adler32 { val: 1 }
}
pub const fn with_initial(val: u32) -> Adler32 {
Adler32 { val }
}
pub fn update(&mut self, data: &[u8]) {
unsafe
{
self.val = libdeflate_adler32(self.val,
data.as_ptr() as *const core::ffi::c_void,
data.len());
}
}
pub const fn sum(&self) -> u32 {
self.val
}
}
pub fn adler32(data:&[u8]) -> u32 {
let mut adler32 = Adler32::new();
adler32.update(&data);
adler32.sum()
}