#![cfg_attr(doc_cfg, feature(doc_cfg))]
mod autodetect;
#[cfg(feature = "bgzip")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "bgzip")))]
pub mod bgzip;
#[cfg(feature = "bzip2")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "bzip2")))]
pub mod bzip2;
mod error;
#[cfg(feature = "flate2")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "gzip")))]
pub mod gzip;
#[cfg(feature = "xz")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "xz")))]
pub mod xz;
#[cfg(feature = "flate2")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "gzip")))]
pub mod zlib;
#[cfg(feature = "zstd")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "zstd")))]
pub mod zstd;
pub mod io;
pub use autodetect::*;
pub use error::{Error, Result};
pub(crate) trait ReadExt: std::io::Read {
fn read_u8(&mut self) -> std::io::Result<u8> {
let mut buf = [0u8; 1];
self.read_exact(&mut buf)?;
Ok(buf[0])
}
fn read_u16_le(&mut self) -> std::io::Result<u16> {
let mut buf = [0u8; 2];
self.read_exact(&mut buf)?;
Ok(u16::from_le_bytes(buf))
}
fn read_u32_le(&mut self) -> std::io::Result<u32> {
let mut buf = [0u8; 4];
self.read_exact(&mut buf)?;
Ok(u32::from_le_bytes(buf))
}
}
impl<T: std::io::Read> ReadExt for T {}
pub(crate) trait WriteExt: std::io::Write {
fn write_u8(&mut self, value: u8) -> std::io::Result<()> {
self.write_all(&[value])
}
fn write_u16_le(&mut self, value: u16) -> std::io::Result<()> {
self.write_all(&value.to_le_bytes())
}
fn write_u32_le(&mut self, value: u32) -> std::io::Result<()> {
self.write_all(&value.to_le_bytes())
}
}
impl<T: std::io::Write> WriteExt for T {}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Status {
Ok,
StreamEnd,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Flush {
None,
Finish,
}
pub trait Processor: Unpin {
fn total_in(&self) -> u64;
fn total_out(&self) -> u64;
fn process(&mut self, input: &[u8], output: &mut [u8], flush: Flush) -> Result<Status>;
fn reset(&mut self);
}
impl Processor for Box<dyn Processor> {
fn process(&mut self, input: &[u8], output: &mut [u8], flush: Flush) -> Result<Status> {
self.as_mut().process(input, output, flush)
}
fn reset(&mut self) {
self.as_mut().reset()
}
fn total_in(&self) -> u64 {
self.as_ref().total_in()
}
fn total_out(&self) -> u64 {
self.as_ref().total_out()
}
}
impl Processor for Box<dyn Processor + Unpin + Send> {
fn process(&mut self, input: &[u8], output: &mut [u8], flush: Flush) -> Result<Status> {
self.as_mut().process(input, output, flush)
}
fn reset(&mut self) {
self.as_mut().reset()
}
fn total_in(&self) -> u64 {
self.as_ref().total_in()
}
fn total_out(&self) -> u64 {
self.as_ref().total_out()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct PlainProcessor {
total_in: u64,
total_out: u64,
}
impl PlainProcessor {
pub fn new() -> Self {
Self::default()
}
}
impl Processor for PlainProcessor {
fn total_in(&self) -> u64 {
self.total_in
}
fn total_out(&self) -> u64 {
self.total_out
}
fn process(&mut self, input: &[u8], output: &mut [u8], flush: Flush) -> Result<Status> {
let len = std::cmp::min(input.len(), output.len());
output[..len].copy_from_slice(&input[..len]);
self.total_in += TryInto::<u64>::try_into(len).unwrap();
self.total_out += TryInto::<u64>::try_into(len).unwrap();
match flush {
Flush::None => Ok(Status::Ok),
Flush::Finish => Ok(Status::StreamEnd),
}
}
fn reset(&mut self) {
self.total_in = 0;
self.total_out = 0;
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum CompressionLevel {
Fastest,
Fast,
Default,
High,
Highest,
}
impl Default for CompressionLevel {
fn default() -> Self {
Self::Default
}
}
impl CompressionLevel {
pub fn fast() -> Self {
Self::Fastest
}
pub fn best() -> Self {
Self::Highest
}
#[cfg_attr(doc_cfg, doc(cfg(feature = "gzip")))]
#[cfg(feature = "flate2")]
pub fn flate2(self) -> flate2::Compression {
match self {
Self::Fastest => flate2::Compression::fast(),
Self::Fast => flate2::Compression::new(3),
Self::Default => flate2::Compression::default(),
Self::High => flate2::Compression::new(7),
Self::Highest => flate2::Compression::best(),
}
}
#[cfg_attr(doc_cfg, doc(cfg(feature = "bgzip")))]
#[cfg(feature = "bgzip")]
pub fn bgzip(self) -> ::bgzip::Compression {
match self {
Self::Fastest => ::bgzip::Compression::fast(),
Self::Fast => ::bgzip::Compression::new(3).expect("Unexpected compression level"),
Self::Default => ::bgzip::Compression::default(),
Self::High => ::bgzip::Compression::new(7).expect("Unexpected compression level"),
Self::Highest => ::bgzip::Compression::best(),
}
}
#[cfg_attr(doc_cfg, doc(cfg(feature = "bzip2")))]
#[cfg(feature = "bzip2")]
pub fn bzip2(self) -> ::bzip2::Compression {
match self {
Self::Fastest => ::bzip2::Compression::fast(),
Self::Fast => ::bzip2::Compression::new(3),
Self::Default => ::bzip2::Compression::default(),
Self::High => ::bzip2::Compression::new(7),
Self::Highest => ::bzip2::Compression::best(),
}
}
#[cfg_attr(doc_cfg, doc(cfg(feature = "xz")))]
#[cfg(feature = "xz")]
pub fn xz(self) -> u32 {
match self {
Self::Fastest => 1,
Self::Fast => 3,
Self::Default => 6,
Self::High => 7,
Self::Highest => 9,
}
}
#[cfg_attr(doc_cfg, doc(cfg(feature = "zstd")))]
#[cfg(feature = "zstd")]
pub fn zstd(self) -> i32 {
match self {
Self::Fastest => 1,
Self::Fast => 2,
Self::Default => ::zstd::DEFAULT_COMPRESSION_LEVEL,
Self::High => 7,
Self::Highest => 9,
}
}
}
#[cfg(test)]
mod tests;