alpm_compress/decompression/
settings.rs

1//! Settings for a compression decoder.
2
3use std::{fmt::Debug, path::Path};
4
5use alpm_types::CompressionAlgorithmFileExtension;
6
7use crate::{compression::CompressionSettings, error::Error};
8
9/// Settings for a compression decoder.
10#[derive(Clone, Debug, Eq, PartialEq)]
11pub enum DecompressionSettings {
12    /// The bzip2 compression algorithm.
13    Bzip2,
14    /// The gzip compression algorithm.
15    Gzip,
16    /// The xz compression algorithm.
17    Xz,
18    /// The zstandard compression algorithm.
19    Zstd,
20    /// No compression.
21    None,
22}
23
24impl TryFrom<CompressionAlgorithmFileExtension> for DecompressionSettings {
25    type Error = Error;
26
27    /// Converts a [`CompressionAlgorithmFileExtension`] into a [`DecompressionSettings`].
28    fn try_from(value: CompressionAlgorithmFileExtension) -> Result<Self, Self::Error> {
29        match value {
30            CompressionAlgorithmFileExtension::Bzip2 => Ok(Self::Bzip2),
31            CompressionAlgorithmFileExtension::Gzip => Ok(Self::Gzip),
32            CompressionAlgorithmFileExtension::Xz => Ok(Self::Xz),
33            CompressionAlgorithmFileExtension::Zstd => Ok(Self::Zstd),
34            _ => Err(Error::UnsupportedCompressionAlgorithm {
35                value: value.to_string(),
36            }),
37        }
38    }
39}
40
41impl TryFrom<&Path> for DecompressionSettings {
42    type Error = Error;
43
44    /// Converts a [`Path`] into a [`DecompressionSettings`] by extracting the file extension.
45    ///
46    /// Delegates deducing the compression algorithm to
47    /// [`CompressionAlgorithmFileExtension::try_from`] and the final conversion to
48    /// [`TryFrom<CompressionAlgorithmFileExtension>`][`TryFrom::try_from`].
49    ///
50    /// # Errors
51    ///
52    /// Returns an error if the compression algorithm file extension is unknown or unsupported.
53    fn try_from(path: &Path) -> Result<Self, Self::Error> {
54        let ext = CompressionAlgorithmFileExtension::try_from(path)
55            .map_err(Error::UnknownCompressionAlgorithmFileExtension)?;
56        DecompressionSettings::try_from(ext)
57    }
58}
59
60impl From<&CompressionSettings> for DecompressionSettings {
61    /// Converts a [`CompressionSettings`] into a [`DecompressionSettings`].
62    fn from(value: &CompressionSettings) -> Self {
63        match value {
64            CompressionSettings::Bzip2 { .. } => DecompressionSettings::Bzip2,
65            CompressionSettings::Gzip { .. } => DecompressionSettings::Gzip,
66            CompressionSettings::Xz { .. } => DecompressionSettings::Xz,
67            CompressionSettings::Zstd { .. } => DecompressionSettings::Zstd,
68            CompressionSettings::None => DecompressionSettings::None,
69        }
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use rstest::rstest;
76    use testresult::TestResult;
77
78    use super::*;
79    use crate::compression::{
80        Bzip2CompressionLevel,
81        GzipCompressionLevel,
82        XzCompressionLevel,
83        ZstdCompressionLevel,
84        ZstdThreads,
85    };
86
87    /// Ensures that the conversion from [`CompressionAlgorithmFileExtension`] to
88    /// [`DecompressionSettings`] works as expected.
89    #[rstest]
90    #[case(CompressionAlgorithmFileExtension::Bzip2, DecompressionSettings::Bzip2)]
91    #[case(CompressionAlgorithmFileExtension::Gzip, DecompressionSettings::Gzip)]
92    #[case(CompressionAlgorithmFileExtension::Xz, DecompressionSettings::Xz)]
93    #[case(CompressionAlgorithmFileExtension::Zstd, DecompressionSettings::Zstd)]
94    fn test_decompression_settings_conversion_success(
95        #[case] ext: CompressionAlgorithmFileExtension,
96        #[case] expected: DecompressionSettings,
97    ) -> TestResult {
98        let result = DecompressionSettings::try_from(ext)?;
99        assert_eq!(result, expected);
100        Ok(())
101    }
102
103    /// Ensures that the conversion from [`CompressionAlgorithmFileExtension`] to
104    /// [`DecompressionSettings`] fails as expected for unsupported algorithms.
105    #[rstest]
106    #[case(CompressionAlgorithmFileExtension::Compress, "Z")]
107    #[case(CompressionAlgorithmFileExtension::Lrzip, "lrz")]
108    #[case(CompressionAlgorithmFileExtension::Lzip, "lz")]
109    #[case(CompressionAlgorithmFileExtension::Lz4, "lz4")]
110    #[case(CompressionAlgorithmFileExtension::Lzop, "lzo")]
111    fn test_decompression_settings_conversion_failure(
112        #[case] ext: CompressionAlgorithmFileExtension,
113        #[case] expected_str: &str,
114    ) -> TestResult {
115        match DecompressionSettings::try_from(ext) {
116            Ok(settings) => Err(format!("Expected failure, but got: {settings:?}").into()),
117            Err(Error::UnsupportedCompressionAlgorithm { value }) => {
118                assert_eq!(value, expected_str);
119                Ok(())
120            }
121            Err(e) => Err(format!("Unexpected error variant: {e:?}").into()),
122        }
123    }
124
125    /// Ensures that the conversion from [`CompressionSettings`] to
126    /// [`DecompressionSettings`] works as expected.
127    #[rstest]
128    #[case::bzip2(CompressionSettings::Bzip2 {
129        compression_level: Bzip2CompressionLevel::default()
130    }, DecompressionSettings::Bzip2)]
131    #[case::gzip(CompressionSettings::Gzip {
132        compression_level: GzipCompressionLevel::default()
133    }, DecompressionSettings::Gzip)]
134    #[case::xz(CompressionSettings::Xz {
135        compression_level: XzCompressionLevel::default()
136    }, DecompressionSettings::Xz)]
137    #[case::zstd(CompressionSettings::Zstd {
138        compression_level: ZstdCompressionLevel::default(),
139        threads: ZstdThreads::new(4),
140    }, DecompressionSettings::Zstd)]
141    #[case(CompressionSettings::None, DecompressionSettings::None)]
142    fn test_from_compression_settings_to_decompression_settings(
143        #[case] settings: CompressionSettings,
144        #[case] expected: DecompressionSettings,
145    ) -> TestResult {
146        let result = DecompressionSettings::from(&settings);
147        assert_eq!(result, expected);
148        Ok(())
149    }
150}