Skip to main content

alpm_compress/decompression/
settings.rs

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