alpm_types/
compression.rs1use std::{
4 path::{Path, PathBuf},
5 str::FromStr,
6};
7
8use alpm_parsers::{iter_str_context, traits::AlpmParser};
9#[cfg(feature = "serde")]
10use serde::{Deserialize, Serialize};
11use strum::{AsRefStr, Display, EnumString, IntoStaticStr, VariantNames};
12use winnow::{
13 Parser,
14 ascii::alphanumeric1,
15 error::{ContextError, ErrMode, StrContext, StrContextValue},
16};
17
18#[derive(
26 AsRefStr,
27 Clone,
28 Copy,
29 Debug,
30 Default,
31 Display,
32 EnumString,
33 Eq,
34 IntoStaticStr,
35 PartialEq,
36 VariantNames,
37)]
38#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
39pub enum CompressionAlgorithmFileExtension {
40 #[cfg_attr(feature = "serde", serde(rename = "Z"))]
44 #[strum(to_string = "Z")]
45 Compress,
46
47 #[cfg_attr(feature = "serde", serde(rename = "bz2"))]
51 #[strum(to_string = "bz2")]
52 Bzip2,
53
54 #[cfg_attr(feature = "serde", serde(rename = "gz"))]
58 #[strum(to_string = "gz")]
59 Gzip,
60
61 #[cfg_attr(feature = "serde", serde(rename = "lrz"))]
65 #[strum(to_string = "lrz")]
66 Lrzip,
67
68 #[cfg_attr(feature = "serde", serde(rename = "lz"))]
72 #[strum(to_string = "lz")]
73 Lzip,
74
75 #[cfg_attr(feature = "serde", serde(rename = "lz4"))]
79 #[strum(to_string = "lz4")]
80 Lz4,
81
82 #[cfg_attr(feature = "serde", serde(rename = "lzo"))]
86 #[strum(to_string = "lzo")]
87 Lzop,
88
89 #[cfg_attr(feature = "serde", serde(rename = "xz"))]
93 #[strum(to_string = "xz")]
94 Xz,
95
96 #[default]
100 #[cfg_attr(feature = "serde", serde(rename = "zst"))]
101 #[strum(to_string = "zst")]
102 Zstd,
103}
104
105impl AlpmParser for CompressionAlgorithmFileExtension {
106 fn parser(input: &mut &str) -> Result<Self, ErrMode<ContextError>> {
113 alphanumeric1
114 .try_map(CompressionAlgorithmFileExtension::from_str)
115 .context(StrContext::Label("compression algorithm file extension"))
116 .context_with(iter_str_context!([
117 CompressionAlgorithmFileExtension::VARIANTS
118 ]))
119 .parse_next(input)
120 }
121
122 fn delimiter_error_context<'a, O, P>(
123 parser: P,
124 ) -> impl Parser<&'a str, O, ErrMode<ContextError>>
125 where
126 P: Parser<&'a str, O, ErrMode<ContextError>>,
127 {
128 parser
129 .context(StrContext::Label("compression algorithm file extension"))
130 .context(StrContext::Expected(StrContextValue::Description(
131 "an alphanumeric string",
132 )))
133 }
134}
135
136impl TryFrom<&Path> for CompressionAlgorithmFileExtension {
137 type Error = crate::Error;
138
139 fn try_from(path: &Path) -> Result<Self, Self::Error> {
147 path.extension()
148 .and_then(|ext| ext.to_str())
149 .and_then(|ext| Self::from_str(ext).ok())
150 .ok_or(strum::ParseError::VariantNotFound.into())
151 }
152}
153
154impl TryFrom<PathBuf> for CompressionAlgorithmFileExtension {
155 type Error = crate::Error;
156
157 fn try_from(path: PathBuf) -> Result<Self, Self::Error> {
167 path.as_path().try_into()
168 }
169}
170
171#[cfg(test)]
172mod tests {
173 use rstest::*;
174
175 use super::*;
176
177 #[rstest]
178 #[case("Z", CompressionAlgorithmFileExtension::Compress)]
179 #[case("bz2", CompressionAlgorithmFileExtension::Bzip2)]
180 #[case("gz", CompressionAlgorithmFileExtension::Gzip)]
181 #[case("lrz", CompressionAlgorithmFileExtension::Lrzip)]
182 #[case("lz", CompressionAlgorithmFileExtension::Lzip)]
183 #[case("lz4", CompressionAlgorithmFileExtension::Lz4)]
184 #[case("lzo", CompressionAlgorithmFileExtension::Lzop)]
185 #[case("xz", CompressionAlgorithmFileExtension::Xz)]
186 #[case("zst", CompressionAlgorithmFileExtension::Zstd)]
187 fn compression_algorithm_file_extension_from_str(
188 #[case] input: &str,
189 #[case] expected: CompressionAlgorithmFileExtension,
190 ) {
191 let parsed = CompressionAlgorithmFileExtension::from_str(input).unwrap();
192 assert_eq!(parsed, expected);
193 }
194
195 #[rstest]
196 #[case("archive.Z", CompressionAlgorithmFileExtension::Compress)]
197 #[case("data.bz2", CompressionAlgorithmFileExtension::Bzip2)]
198 #[case("doc.gz", CompressionAlgorithmFileExtension::Gzip)]
199 #[case("video.lrz", CompressionAlgorithmFileExtension::Lrzip)]
200 #[case("binary.lz", CompressionAlgorithmFileExtension::Lzip)]
201 #[case("dump.lz4", CompressionAlgorithmFileExtension::Lz4)]
202 #[case("image.lzo", CompressionAlgorithmFileExtension::Lzop)]
203 #[case("package.xz", CompressionAlgorithmFileExtension::Xz)]
204 #[case("/var/cache/repo.zst", CompressionAlgorithmFileExtension::Zstd)]
205 fn compression_algorithm_file_extension_try_from_path(
206 #[case] filename: &str,
207 #[case] expected: CompressionAlgorithmFileExtension,
208 ) -> testresult::TestResult {
209 let path = PathBuf::from(filename);
210 let parsed = CompressionAlgorithmFileExtension::try_from(path)?;
211 assert_eq!(parsed, expected);
212 Ok(())
213 }
214
215 #[rstest]
216 #[case("file.txt")]
217 #[case("unknown.abc")]
218 #[case("noext")]
219 fn invalid_compression_file_extension(#[case] filename: &str) {
220 let path = Path::new(filename);
221 let error = CompressionAlgorithmFileExtension::try_from(path).unwrap_err();
222 assert!(matches!(error, crate::Error::InvalidVariant(_)));
223 }
224}