alpm_types/
system.rs

1use std::str::FromStr;
2
3use alpm_parsers::iter_str_context;
4use serde::{Deserialize, Serialize};
5use strum::{Display, EnumString, VariantNames};
6use winnow::{
7    ModalResult,
8    Parser,
9    combinator::cut_err,
10    error::{StrContext, StrContextValue},
11    token::rest,
12};
13
14/// CPU architecture
15///
16/// Members of the Architecture enum can be created from `&str`.
17///
18/// ## Examples
19/// ```
20/// use std::str::FromStr;
21///
22/// use alpm_types::Architecture;
23///
24/// // create Architecture from str
25/// assert_eq!(Architecture::from_str("aarch64"), Ok(Architecture::Aarch64));
26///
27/// // format as String
28/// assert_eq!("aarch64", format!("{}", Architecture::Aarch64));
29/// assert_eq!("any", format!("{}", Architecture::Any));
30/// assert_eq!("arm", format!("{}", Architecture::Arm));
31/// assert_eq!("armv6h", format!("{}", Architecture::Armv6h));
32/// assert_eq!("armv7h", format!("{}", Architecture::Armv7h));
33/// assert_eq!("i386", format!("{}", Architecture::I386));
34/// assert_eq!("i486", format!("{}", Architecture::I486));
35/// assert_eq!("i686", format!("{}", Architecture::I686));
36/// assert_eq!("pentium4", format!("{}", Architecture::Pentium4));
37/// assert_eq!("riscv32", format!("{}", Architecture::Riscv32));
38/// assert_eq!("riscv64", format!("{}", Architecture::Riscv64));
39/// assert_eq!("x86_64", format!("{}", Architecture::X86_64));
40/// assert_eq!("x86_64_v2", format!("{}", Architecture::X86_64V2));
41/// assert_eq!("x86_64_v3", format!("{}", Architecture::X86_64V3));
42/// assert_eq!("x86_64_v4", format!("{}", Architecture::X86_64V4));
43/// ```
44#[derive(
45    Clone,
46    Copy,
47    Debug,
48    Deserialize,
49    Display,
50    EnumString,
51    Eq,
52    Hash,
53    Ord,
54    PartialEq,
55    PartialOrd,
56    Serialize,
57    VariantNames,
58)]
59#[strum(serialize_all = "lowercase")]
60#[serde(rename_all = "lowercase")]
61pub enum Architecture {
62    /// ARMv8 64-bit
63    Aarch64,
64    /// Any architecture
65    Any,
66    /// ARM
67    Arm,
68    /// ARMv6 hard-float
69    Armv6h,
70    /// ARMv7 hard-float
71    Armv7h,
72    /// Intel 386
73    I386,
74    /// Intel 486
75    I486,
76    /// Intel 686
77    I686,
78    /// Intel Pentium 4
79    Pentium4,
80    /// RISC-V 32-bit
81    Riscv32,
82    /// RISC-V 64-bit
83    Riscv64,
84    /// Intel x86_64
85    X86_64,
86    /// Intel x86_64 version 2
87    #[strum(to_string = "x86_64_v2")]
88    X86_64V2,
89    /// Intel x86_64 version 3
90    #[strum(to_string = "x86_64_v3")]
91    X86_64V3,
92    /// Intel x86_64 version 4
93    #[strum(to_string = "x86_64_v4")]
94    X86_64V4,
95}
96
97impl Architecture {
98    /// Recognizes an [`Architecture`] in an input string.
99    ///
100    /// Consumes all input and returns an error if the string doesn't match any architecture.
101    pub fn parser(input: &mut &str) -> ModalResult<Architecture> {
102        cut_err(rest.try_map(Architecture::from_str))
103            .context(StrContext::Label("architecture"))
104            .context(StrContext::Expected(StrContextValue::Description(
105                "an alpm-architecture:",
106            )))
107            .context_with(iter_str_context!([Architecture::VARIANTS]))
108            .parse_next(input)
109    }
110}
111
112/// ELF architecture format.
113///
114/// This enum represents the _Class_ field in the [_ELF Header_].
115///
116/// ## Examples
117///
118/// ```
119/// use std::str::FromStr;
120///
121/// use alpm_types::ElfArchitectureFormat;
122///
123/// # fn main() -> Result<(), alpm_types::Error> {
124/// // create ElfArchitectureFormat from str
125/// assert_eq!(
126///     ElfArchitectureFormat::from_str("32"),
127///     Ok(ElfArchitectureFormat::Bit32)
128/// );
129/// assert_eq!(
130///     ElfArchitectureFormat::from_str("64"),
131///     Ok(ElfArchitectureFormat::Bit64)
132/// );
133///
134/// // format as String
135/// assert_eq!("32", format!("{}", ElfArchitectureFormat::Bit32));
136/// assert_eq!("64", format!("{}", ElfArchitectureFormat::Bit64));
137/// # Ok(())
138/// # }
139/// ```
140///
141/// [_ELF Header_]: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#ELF_header
142#[derive(
143    Clone, Copy, Debug, Deserialize, Display, EnumString, Eq, Ord, PartialEq, PartialOrd, Serialize,
144)]
145#[strum(serialize_all = "lowercase")]
146pub enum ElfArchitectureFormat {
147    /// 32-bit
148    #[strum(to_string = "32")]
149    Bit32 = 32,
150    /// 64-bit
151    #[strum(to_string = "64")]
152    Bit64 = 64,
153}
154
155#[cfg(test)]
156mod tests {
157    use std::str::FromStr;
158
159    use rstest::rstest;
160    use strum::ParseError;
161    use winnow::error::ContextError;
162
163    use super::*;
164
165    #[rstest]
166    #[case("aarch64", Ok(Architecture::Aarch64))]
167    #[case("any", Ok(Architecture::Any))]
168    #[case("arm", Ok(Architecture::Arm))]
169    #[case("armv6h", Ok(Architecture::Armv6h))]
170    #[case("armv7h", Ok(Architecture::Armv7h))]
171    #[case("i386", Ok(Architecture::I386))]
172    #[case("i486", Ok(Architecture::I486))]
173    #[case("i686", Ok(Architecture::I686))]
174    #[case("pentium4", Ok(Architecture::Pentium4))]
175    #[case("riscv32", Ok(Architecture::Riscv32))]
176    #[case("riscv64", Ok(Architecture::Riscv64))]
177    #[case("x86_64", Ok(Architecture::X86_64))]
178    #[case("x86_64_v2", Ok(Architecture::X86_64V2))]
179    #[case("x86_64_v3", Ok(Architecture::X86_64V3))]
180    #[case("x86_64_v4", Ok(Architecture::X86_64V4))]
181    #[case("foo", Err(ParseError::VariantNotFound))]
182    fn architecture_from_string(#[case] s: &str, #[case] arch: Result<Architecture, ParseError>) {
183        assert_eq!(Architecture::from_str(s), arch);
184    }
185
186    #[rstest]
187    #[case("aarch64", Ok(Architecture::Aarch64))]
188    #[case("any", Ok(Architecture::Any))]
189    #[case("arm", Ok(Architecture::Arm))]
190    #[case("armv6h", Ok(Architecture::Armv6h))]
191    #[case("armv7h", Ok(Architecture::Armv7h))]
192    #[case("i386", Ok(Architecture::I386))]
193    #[case("i486", Ok(Architecture::I486))]
194    #[case("i686", Ok(Architecture::I686))]
195    #[case("pentium4", Ok(Architecture::Pentium4))]
196    #[case("riscv32", Ok(Architecture::Riscv32))]
197    #[case("riscv64", Ok(Architecture::Riscv64))]
198    #[case("x86_64", Ok(Architecture::X86_64))]
199    #[case("x86_64_v2", Ok(Architecture::X86_64V2))]
200    #[case("x86_64_v3", Ok(Architecture::X86_64V3))]
201    #[case("x86_64_v4", Ok(Architecture::X86_64V4))]
202    fn architecture_parser(
203        #[case] s: &str,
204        #[case] arch: Result<Architecture, winnow::error::ParseError<&str, ContextError>>,
205    ) {
206        assert_eq!(Architecture::parser.parse(s), arch);
207    }
208
209    #[rstest]
210    #[case(Architecture::Aarch64, "aarch64")]
211    #[case(Architecture::Any, "any")]
212    #[case(Architecture::Arm, "arm")]
213    #[case(Architecture::Armv6h, "armv6h")]
214    #[case(Architecture::Armv7h, "armv7h")]
215    #[case(Architecture::I386, "i386")]
216    #[case(Architecture::I486, "i486")]
217    #[case(Architecture::I686, "i686")]
218    #[case(Architecture::Pentium4, "pentium4")]
219    #[case(Architecture::Riscv32, "riscv32")]
220    #[case(Architecture::Riscv64, "riscv64")]
221    #[case(Architecture::X86_64, "x86_64")]
222    #[case(Architecture::X86_64V2, "x86_64_v2")]
223    #[case(Architecture::X86_64V3, "x86_64_v3")]
224    #[case(Architecture::X86_64V4, "x86_64_v4")]
225    fn architecture_format_string(#[case] arch: Architecture, #[case] arch_str: &str) {
226        assert_eq!(arch_str, format!("{arch}"));
227    }
228
229    #[rstest]
230    #[case("32", Ok(ElfArchitectureFormat::Bit32))]
231    #[case("64", Ok(ElfArchitectureFormat::Bit64))]
232    #[case("foo", Err(ParseError::VariantNotFound))]
233    fn elf_architecture_format_from_string(
234        #[case] s: &str,
235        #[case] arch: Result<ElfArchitectureFormat, ParseError>,
236    ) {
237        assert_eq!(ElfArchitectureFormat::from_str(s), arch);
238    }
239
240    #[rstest]
241    #[case(ElfArchitectureFormat::Bit32, "32")]
242    #[case(ElfArchitectureFormat::Bit64, "64")]
243    fn elf_architecture_format_display(
244        #[case] arch: ElfArchitectureFormat,
245        #[case] arch_str: &str,
246    ) {
247        assert_eq!(arch_str, format!("{arch}"));
248    }
249}