Skip to main content

upstream_rs/utils/
platform_info.rs

1use std::fmt;
2use std::str::FromStr;
3
4#[derive(Debug, Clone, PartialEq, Eq)]
5pub enum OSKind {
6    Windows,
7    MacOS,
8    Linux,
9    FreeBSD,
10    OpenBSD,
11    NetBSD,
12    Android,
13    Ios,
14    Unknown,
15}
16
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub enum CpuArch {
19    X86,
20    X86_64,
21    Arm,
22    Aarch64,
23    Ppc,
24    Ppc64,
25    Riscv64,
26    S390x,
27    Unknown,
28}
29
30#[derive(Debug, Clone, PartialEq, Eq)]
31pub struct ParseCpuArchError;
32
33impl fmt::Display for ParseCpuArchError {
34    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35        write!(f, "failed to parse CPU architecture")
36    }
37}
38
39impl std::error::Error for ParseCpuArchError {}
40
41impl FromStr for CpuArch {
42    type Err = ParseCpuArchError;
43
44    fn from_str(s: &str) -> Result<Self, Self::Err> {
45        match s {
46            "x86" => Ok(Self::X86),
47            "x86_64" => Ok(Self::X86_64),
48            "arm" => Ok(Self::Arm),
49            "aarch64" => Ok(Self::Aarch64),
50            "powerpc" => Ok(Self::Ppc),
51            "powerpc64" => Ok(Self::Ppc64),
52            "riscv64" => Ok(Self::Riscv64),
53            "s390x" => Ok(Self::S390x),
54            _ => Ok(Self::Unknown),
55        }
56    }
57}
58
59impl FromStr for OSKind {
60    type Err = ();
61
62    fn from_str(s: &str) -> Result<Self, Self::Err> {
63        match s {
64            "windows" => Ok(Self::Windows),
65            "macos" => Ok(Self::MacOS),
66            "linux" => Ok(Self::Linux),
67            "freebsd" => Ok(Self::FreeBSD),
68            "openbsd" => Ok(Self::OpenBSD),
69            "netbsd" => Ok(Self::NetBSD),
70            "android" => Ok(Self::Android),
71            "ios" => Ok(Self::Ios),
72            _ => Ok(Self::Unknown),
73        }
74    }
75}
76
77#[derive(Debug, Clone, PartialEq, Eq)]
78pub struct ArchitectureInfo {
79    pub is_os_64_bit: bool,
80    pub cpu_arch: CpuArch,
81    pub os_kind: OSKind,
82}
83
84impl ArchitectureInfo {
85    pub fn new_compiletime() -> Self {
86        let is_os_64_bit = cfg!(target_pointer_width = "64");
87
88        #[cfg(target_arch = "x86")]
89        let cpu_arch = CpuArch::X86;
90        #[cfg(target_arch = "x86_64")]
91        let cpu_arch = CpuArch::X86_64;
92        #[cfg(target_arch = "arm")]
93        let cpu_arch = CpuArch::Arm;
94        #[cfg(target_arch = "aarch64")]
95        let cpu_arch = CpuArch::Aarch64;
96        #[cfg(target_arch = "powerpc")]
97        let cpu_arch = CpuArch::Ppc;
98        #[cfg(target_arch = "powerpc64")]
99        let cpu_arch = CpuArch::Ppc64;
100        #[cfg(target_arch = "riscv64")]
101        let cpu_arch = CpuArch::Riscv64;
102        #[cfg(target_arch = "s390x")]
103        let cpu_arch = CpuArch::S390x;
104        #[cfg(not(any(
105            target_arch = "x86",
106            target_arch = "x86_64",
107            target_arch = "arm",
108            target_arch = "aarch64",
109            target_arch = "powerpc",
110            target_arch = "powerpc64",
111            target_arch = "riscv64",
112            target_arch = "s390x"
113        )))]
114        let cpu_arch = CpuArch::Unknown;
115
116        #[cfg(target_os = "windows")]
117        let os_kind = OSKind::Windows;
118        #[cfg(target_os = "macos")]
119        let os_kind = OSKind::MacOS;
120        #[cfg(target_os = "linux")]
121        let os_kind = OSKind::Linux;
122        #[cfg(target_os = "freebsd")]
123        let os_kind = OSKind::FreeBSD;
124        #[cfg(target_os = "openbsd")]
125        let os_kind = OSKind::OpenBSD;
126        #[cfg(target_os = "netbsd")]
127        let os_kind = OSKind::NetBSD;
128        #[cfg(target_os = "android")]
129        let os_kind = OSKind::Android;
130        #[cfg(target_os = "ios")]
131        let os_kind = OSKind::Ios;
132        #[cfg(not(any(
133            target_os = "windows",
134            target_os = "macos",
135            target_os = "linux",
136            target_os = "freebsd",
137            target_os = "openbsd",
138            target_os = "netbsd",
139            target_os = "android",
140            target_os = "ios"
141        )))]
142        let os_kind = OSKind::Unknown;
143
144        Self {
145            is_os_64_bit,
146            cpu_arch,
147            os_kind,
148        }
149    }
150
151    pub fn new() -> Self {
152        Self::new_compiletime()
153    }
154}
155
156impl Default for ArchitectureInfo {
157    fn default() -> Self {
158        Self::new()
159    }
160}
161
162pub fn format_arch(arch: &CpuArch) -> &str {
163    match arch {
164        CpuArch::X86 => "x86",
165        CpuArch::X86_64 => "x86_64",
166        CpuArch::Arm => "ARM",
167        CpuArch::Aarch64 => "ARM64",
168        CpuArch::Ppc => "PowerPC",
169        CpuArch::Ppc64 => "PowerPC64",
170        CpuArch::Riscv64 => "RISC-V 64",
171        CpuArch::S390x => "s390x",
172        CpuArch::Unknown => "Unknown",
173    }
174}
175
176pub fn format_os(os: &OSKind) -> &str {
177    match os {
178        OSKind::Windows => "Windows",
179        OSKind::MacOS => "macOS",
180        OSKind::Linux => "Linux",
181        OSKind::FreeBSD => "FreeBSD",
182        OSKind::OpenBSD => "OpenBSD",
183        OSKind::NetBSD => "NetBSD",
184        OSKind::Android => "Android",
185        OSKind::Ios => "iOS",
186        OSKind::Unknown => "Unknown OS",
187    }
188}
189
190#[cfg(test)]
191mod tests {
192    use super::{ArchitectureInfo, CpuArch, OSKind, format_arch, format_os};
193    use std::str::FromStr;
194
195    #[test]
196    fn cpu_arch_from_str_maps_known_and_unknown_values() {
197        assert_eq!(CpuArch::from_str("x86").expect("x86 parse"), CpuArch::X86);
198        assert_eq!(
199            CpuArch::from_str("aarch64").expect("aarch64 parse"),
200            CpuArch::Aarch64
201        );
202        assert_eq!(
203            CpuArch::from_str("something-else").expect("unknown parse"),
204            CpuArch::Unknown
205        );
206    }
207
208    #[test]
209    fn os_kind_from_str_maps_known_and_unknown_values() {
210        assert_eq!(
211            OSKind::from_str("windows").expect("windows parse"),
212            OSKind::Windows
213        );
214        assert_eq!(
215            OSKind::from_str("linux").expect("linux parse"),
216            OSKind::Linux
217        );
218        assert_eq!(
219            OSKind::from_str("weird-os").expect("unknown parse"),
220            OSKind::Unknown
221        );
222    }
223
224    #[test]
225    fn formatter_outputs_are_stable() {
226        assert_eq!(format_arch(&CpuArch::X86_64), "x86_64");
227        assert_eq!(format_arch(&CpuArch::Unknown), "Unknown");
228        assert_eq!(format_os(&OSKind::MacOS), "macOS");
229        assert_eq!(format_os(&OSKind::Unknown), "Unknown OS");
230    }
231
232    #[test]
233    fn architecture_info_default_constructs_reasonable_values() {
234        let info = ArchitectureInfo::default();
235        assert!(!format_arch(&info.cpu_arch).is_empty());
236        assert!(!format_os(&info.os_kind).is_empty());
237    }
238}