exarch-core 0.4.1

Memory-safe archive extraction library with security validation
Documentation
//! Compression level conversion utilities.
//!
//! This module provides unified conversion from the user-friendly compression
//! level scale (1-9) to codec-specific compression level types.
//!
//! # Level Mapping
//!
//! User levels follow a consistent scale:
//!
//! - **1-3**: Fast compression (lower CPU usage, larger files)
//! - **6**: Default compression (balanced)
//! - **7-9**: Best compression (higher CPU usage, smaller files)
//!
//! Each codec maps these levels to its own internal scale.

/// Converts user compression level (1-9) to flate2 compression level.
///
/// # Mapping
///
/// - `None` or `Some(6)`: Default compression
/// - `1-3`: Fast compression
/// - `7-9`: Best compression
/// - Other values: Literal level (clamped to valid range)
///
/// # Examples
///
/// ```ignore
/// use exarch_core::creation::compression::compression_level_to_flate2;
///
/// let default_level = compression_level_to_flate2(None);
/// let fast_level = compression_level_to_flate2(Some(1));
/// let best_level = compression_level_to_flate2(Some(9));
/// ```
#[must_use]
pub fn compression_level_to_flate2(level: Option<u8>) -> flate2::Compression {
    match level {
        None | Some(6) => flate2::Compression::default(),
        Some(1..=3) => flate2::Compression::fast(),
        Some(7..=9) => flate2::Compression::best(),
        Some(n) => flate2::Compression::new(u32::from(n)),
    }
}

/// Converts user compression level (1-9) to bzip2 compression level.
///
/// # Mapping
///
/// - `None` or `Some(6)`: Default compression
/// - `1`: Fast compression
/// - `2-6`: Literal level
/// - `7-9`: Best compression
///
/// # Examples
///
/// ```ignore
/// use exarch_core::creation::compression::compression_level_to_bzip2;
///
/// let default_level = compression_level_to_bzip2(None);
/// let fast_level = compression_level_to_bzip2(Some(1));
/// let best_level = compression_level_to_bzip2(Some(9));
/// ```
#[must_use]
pub fn compression_level_to_bzip2(level: Option<u8>) -> bzip2::Compression {
    match level {
        None | Some(6) => bzip2::Compression::default(),
        Some(1) => bzip2::Compression::fast(),
        Some(7..=9) => bzip2::Compression::best(),
        Some(n @ 2..=6) => bzip2::Compression::new(u32::from(n)),
        Some(n) => bzip2::Compression::new(u32::from(n.min(9))),
    }
}

/// Converts user compression level (1-9) to xz compression level.
///
/// # Mapping
///
/// - `None` or `Some(6)`: Level 6 (default)
/// - Other values: Literal level (0-9 range supported by xz)
///
/// # Examples
///
/// ```ignore
/// use exarch_core::creation::compression::compression_level_to_xz;
///
/// let default_level = compression_level_to_xz(None);
/// let fast_level = compression_level_to_xz(Some(1));
/// let best_level = compression_level_to_xz(Some(9));
/// ```
#[must_use]
pub fn compression_level_to_xz(level: Option<u8>) -> u32 {
    match level {
        None | Some(6) => 6,
        Some(n) => u32::from(n),
    }
}

/// Converts user compression level (1-9) to zstd compression level.
///
/// # Mapping
///
/// Zstd has a wider range (1-22) than our user scale (1-9).
/// We map user levels to strategic zstd levels:
///
/// - `None` or `Some(6)`: Level 3 (default, fast with good compression)
/// - `1`: Level 1 (fastest)
/// - `2`: Level 2 (fast)
/// - `7`: Level 10 (good compression)
/// - `8`: Level 15 (better compression)
/// - `9`: Level 19 (best compression)
/// - Other values: Level 3 (default)
///
/// # Examples
///
/// ```ignore
/// use exarch_core::creation::compression::compression_level_to_zstd;
///
/// let default_level = compression_level_to_zstd(None);
/// assert_eq!(default_level, 3);
///
/// let fast_level = compression_level_to_zstd(Some(1));
/// assert_eq!(fast_level, 1);
///
/// let best_level = compression_level_to_zstd(Some(9));
/// assert_eq!(best_level, 19);
/// ```
#[allow(clippy::match_same_arms)] // Different semantic meanings for each level
#[must_use]
pub fn compression_level_to_zstd(level: Option<u8>) -> i32 {
    match level {
        // Default compression level
        None | Some(6) => 3,
        Some(1) => 1,
        Some(2) => 2,
        Some(7) => 10,
        Some(8) => 15,
        Some(9) => 19,
        // All other levels (3-5, 0, 10+) map to default
        _ => 3,
    }
}

/// Unified compression level type.
///
/// This enum wraps codec-specific compression level types to provide
/// a unified interface for compression level conversion.
#[derive(Debug, Clone, Copy)]
pub enum CompressionLevel {
    /// Flate2 (gzip) compression level.
    Flate2(flate2::Compression),

    /// Bzip2 compression level.
    Bzip2(bzip2::Compression),

    /// Xz compression level (raw u32).
    Xz(u32),

    /// Zstd compression level (raw i32).
    Zstd(i32),
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_compression_level_to_flate2() {
        // Default
        let level = compression_level_to_flate2(None);
        assert_eq!(level, flate2::Compression::default());

        let level = compression_level_to_flate2(Some(6));
        assert_eq!(level, flate2::Compression::default());

        // Fast
        let level = compression_level_to_flate2(Some(1));
        assert_eq!(level, flate2::Compression::fast());

        // Best
        let level = compression_level_to_flate2(Some(9));
        assert_eq!(level, flate2::Compression::best());

        // Specific level
        let level = compression_level_to_flate2(Some(5));
        assert_eq!(level, flate2::Compression::new(5));
    }

    #[test]
    fn test_compression_level_to_bzip2() {
        // Default
        let level = compression_level_to_bzip2(None);
        assert_eq!(level, bzip2::Compression::default());

        // Fast
        let level = compression_level_to_bzip2(Some(1));
        assert_eq!(level, bzip2::Compression::fast());

        // Best
        let level = compression_level_to_bzip2(Some(9));
        assert_eq!(level, bzip2::Compression::best());

        // Specific level
        let level = compression_level_to_bzip2(Some(4));
        assert_eq!(level, bzip2::Compression::new(4));
    }

    #[test]
    fn test_compression_level_to_xz() {
        assert_eq!(compression_level_to_xz(None), 6);
        assert_eq!(compression_level_to_xz(Some(6)), 6);
        assert_eq!(compression_level_to_xz(Some(1)), 1);
        assert_eq!(compression_level_to_xz(Some(9)), 9);
    }

    #[test]
    fn test_compression_level_to_zstd() {
        assert_eq!(compression_level_to_zstd(None), 3);
        assert_eq!(compression_level_to_zstd(Some(6)), 3);
        assert_eq!(compression_level_to_zstd(Some(1)), 1);
        assert_eq!(compression_level_to_zstd(Some(2)), 2);
        assert_eq!(compression_level_to_zstd(Some(7)), 10);
        assert_eq!(compression_level_to_zstd(Some(8)), 15);
        assert_eq!(compression_level_to_zstd(Some(9)), 19);
    }
}