mod brotli; mod bzip2; mod containers; mod gzip; mod lz4; mod lzma; mod pipeline; mod sevenz; mod snappy; mod stream; mod tar; mod xz; mod zip; mod zstd; pub use brotli::{Brotli, BrotliArgs}; pub use bzip2::{Bzip2, Bzip2Args}; pub use gzip::{Gzip, GzipArgs}; pub use lz4::{Lz4, Lz4Args}; pub use lzma::{Lzma, LzmaArgs}; pub use pipeline::Pipeline; pub use sevenz::{SevenZ, SevenZArgs}; pub use snappy::{Snappy, SnappyArgs}; pub use tar::{Tar, TarArgs}; pub use xz::{Xz, XzArgs}; pub use zip::{Zip, ZipArgs}; pub use zstd::{Zstd, ZstdArgs}; use crate::utils::Compressor; /// Create a default compressor instance from an extension or name string. /// This is the single canonical lookup table for all compressor types. pub fn compressor_from_str(s: &str) -> Option> { match s { "tar" => Some(Box::::default()), "gzip" | "gz" => Some(Box::::default()), "xz" => Some(Box::::default()), "bzip2" | "bz2" => Some(Box::::default()), "zip" => Some(Box::::default()), "zstd" | "zst" => Some(Box::::default()), "lz4" => Some(Box::::default()), "brotli" | "br" => Some(Box::::default()), "snappy" | "sz" => Some(Box::::default()), "lzma" => Some(Box::::default()), "7z" | "sevenz" => Some(Box::::default()), _ => None, } } /// Resolve an extension to a compressor chain in innermost→outermost order. /// Single-codec extensions (`gz`, `xz`, `tar`, …) produce a one-element chain; /// compound shortcut extensions (`tgz`, `tbz`, `tbz2`, `txz`, `tzst`) expand /// into the chain they represent (e.g. `tgz` → `[tar, gz]`). /// /// This is the single source of truth for what any archive-like extension /// means. Both single extensions and compound shortcuts flow through here. pub fn chain_from_ext(ext: &str) -> Option>> { match ext { "tgz" => Some(vec![Box::::default(), Box::::default()]), "tbz" | "tbz2" => Some(vec![Box::::default(), Box::::default()]), "txz" => Some(vec![Box::::default(), Box::::default()]), "tzst" => Some(vec![Box::::default(), Box::::default()]), _ => compressor_from_str(ext).map(|c| vec![c]), } } /// Resolve a dotted format string (e.g. `tar.gz`, `tgz`, `xz`) into a /// compressor chain. Every dot-separated segment is resolved via /// `chain_from_ext` and concatenated in order. Returns `None` if any /// segment isn't a known codec or shortcut. pub fn chain_from_format_str(s: &str) -> Option>> { let mut chain = Vec::new(); for part in s.split('.') { chain.extend(chain_from_ext(part)?); } if chain.is_empty() { None } else { Some(chain) } }