1use std::fmt;
4use std::str::FromStr;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub struct Target {
8 pub architecture: TargetArchitecture,
9 pub operating_system: TargetOperatingSystem,
10}
11
12impl Target {
13 pub fn new(architecture: TargetArchitecture, operating_system: TargetOperatingSystem) -> Self {
14 Self {
15 architecture,
16 operating_system,
17 }
18 }
19
20 pub fn to_str(&self) -> String {
21 format!("{}_{}", self.architecture, self.operating_system)
22 }
23
24 pub fn detect_host() -> Self {
34 use crate::detection::{detect_host_architecture_only, detect_host_os};
35 use std::str::FromStr;
36 let arch = detect_host_architecture_only();
37 let os = detect_host_os();
38 Self::new(
39 TargetArchitecture::from_str(arch).unwrap_or(TargetArchitecture::Unknown),
40 TargetOperatingSystem::from_str(os).unwrap_or(TargetOperatingSystem::Unknown),
41 )
42 }
43}
44
45impl FromStr for Target {
46 type Err = &'static str;
47
48 fn from_str(target: &str) -> Result<Self, Self::Err> {
49 let parts: Vec<&str> = target.rsplitn(2, '_').collect();
50 if parts.len() != 2 {
51 return Err("Invalid target format: expected 'architecture_os'");
52 }
53 Ok(Self::new(
54 TargetArchitecture::from_str(parts[1]).map_err(|_| "Invalid architecture")?,
55 TargetOperatingSystem::from_str(parts[0]).map_err(|_| "Invalid operating system")?,
56 ))
57 }
58}
59
60impl fmt::Display for Target {
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62 write!(f, "{}_{}", self.architecture, self.operating_system)
63 }
64}
65
66#[derive(Debug, Clone, Copy, PartialEq, Eq)]
67pub enum TargetArchitecture {
68 X86_64,
69 Aarch64,
70 Arx64,
71 Arm32,
72 Riscv32,
73 Riscv64,
74 #[cfg(feature = "nightly")]
75 Riscv128,
76 Wasm32,
77 Wasm64,
78 PowerPC64,
79 #[cfg(feature = "nightly")]
80 Lisa,
81 Unknown,
82}
83
84impl FromStr for TargetArchitecture {
85 type Err = &'static str;
86
87 fn from_str(s: &str) -> Result<Self, Self::Err> {
88 match s {
89 "x86_64" => Ok(Self::X86_64),
90 "aarch64" => Ok(Self::Aarch64),
91 "arx64" => Ok(Self::Arx64),
92 "arm32" => Ok(Self::Arm32),
93 "riscv32" => Ok(Self::Riscv32),
94 "riscv64" => Ok(Self::Riscv64),
95 #[cfg(feature = "nightly")]
96 "riscv128" => Ok(Self::Riscv128),
97 "wasm32" => Ok(Self::Wasm32),
98 "wasm64" => Ok(Self::Wasm64),
99 "wasm" => Ok(Self::Wasm32),
100 "ppc64" | "powerpc64" | "ppc64le" => Ok(Self::PowerPC64),
101 #[cfg(feature = "nightly")]
102 "lisa" => Ok(Self::Lisa),
103 _ => Err("Unknown architecture"),
104 }
105 }
106}
107
108#[derive(Debug, Clone, Copy, PartialEq, Eq)]
109pub enum TargetOperatingSystem {
110 Linux,
111 MacOS,
112 Windows,
113 Android,
114 IOS,
115 TvOS,
116 WatchOS,
117 VisionOS,
118 FreeBSD,
119 OpenBSD,
120 NetBSD,
121 DragonFly,
122 Redox,
123 Horizon,
124 Psp,
125 Psx,
126 Vita,
127 #[cfg(feature = "nightly")]
128 Artery,
129 Unknown,
130}
131
132impl FromStr for TargetOperatingSystem {
133 type Err = &'static str;
134
135 fn from_str(s: &str) -> Result<Self, Self::Err> {
136 match s {
137 "linux" => Ok(Self::Linux),
138 "macos" => Ok(Self::MacOS),
139 "windows" => Ok(Self::Windows),
140 "android" => Ok(Self::Android),
141 "ios" => Ok(Self::IOS),
142 "tvos" => Ok(Self::TvOS),
143 "watchos" => Ok(Self::WatchOS),
144 "visionos" => Ok(Self::VisionOS),
145 "freebsd" => Ok(Self::FreeBSD),
146 "openbsd" => Ok(Self::OpenBSD),
147 "netbsd" => Ok(Self::NetBSD),
148 "dragonfly" => Ok(Self::DragonFly),
149 "redox" => Ok(Self::Redox),
150 "horizon" => Ok(Self::Horizon),
151 "psp" => Ok(Self::Psp),
152 "psx" => Ok(Self::Psx),
153 "vita" => Ok(Self::Vita),
154 "unknown" => Ok(Self::Unknown),
155 #[cfg(feature = "nightly")]
156 "artery" => Ok(Self::Artery),
157 "bsd" => Ok(Self::FreeBSD),
158 _ => Err("Unknown operating system"),
159 }
160 }
161}
162
163impl fmt::Display for TargetArchitecture {
164 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
165 let s = match self {
166 Self::X86_64 => "x86_64",
167 Self::Aarch64 => "aarch64",
168 Self::Arx64 => "arx64",
169 Self::Arm32 => "arm32",
170 Self::Riscv32 => "riscv32",
171 Self::Riscv64 => "riscv64",
172 #[cfg(feature = "nightly")]
173 Self::Riscv128 => "riscv128",
174 Self::Wasm32 => "wasm32",
175 Self::Wasm64 => "wasm64",
176 Self::PowerPC64 => "ppc64le",
177 #[cfg(feature = "nightly")]
178 Self::Lisa => "lisa",
179 Self::Unknown => "unknown",
180 };
181 write!(f, "{}", s)
182 }
183}
184
185impl fmt::Display for TargetOperatingSystem {
186 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187 let s = match self {
188 Self::Linux => "linux",
189 Self::MacOS => "macos",
190 Self::Windows => "windows",
191 Self::Android => "android",
192 Self::IOS => "ios",
193 Self::TvOS => "tvos",
194 Self::WatchOS => "watchos",
195 Self::VisionOS => "visionos",
196 Self::FreeBSD => "freebsd",
197 Self::OpenBSD => "openbsd",
198 Self::NetBSD => "netbsd",
199 Self::DragonFly => "dragonfly",
200 Self::Redox => "redox",
201 Self::Horizon => "horizon",
202 Self::Psp => "psp",
203 Self::Psx => "psx",
204 Self::Vita => "vita",
205 #[cfg(feature = "nightly")]
206 Self::Artery => "artery",
207 Self::Unknown => "unknown",
208 };
209 write!(f, "{}", s)
210 }
211}
212
213pub const HOST_ARCH_LIST: &[&str] = &[
214 "x86_64_unknown",
215 "x86_64_linux",
216 "x86_64_windows",
217 "x86_64_macos",
218 "x86_64_android",
219 "x86_64_ios",
220 "x86_64_tvos",
221 "x86_64_watchos",
222 "aarch64_unknown",
223 "aarch64_macos",
224 "aarch64_linux",
225 "aarch64_windows",
226 "aarch64_android",
227 "aarch64_ios",
228 "aarch64_tvos",
229 "aarch64_watchos",
230 "aarch64_visionos",
231 "aarch64_horizon",
232 "arm32_android",
233 "arm32_ios",
234 "arm32_watchos",
235 "arm32_vita",
236 "arx64_unknown",
237 "wasm32_unknown",
238 "wasm64_unknown",
239 "riscv32_unknown",
240 "riscv64_unknown",
241 #[cfg(feature = "nightly")]
242 "riscv128_unknown",
243];
244
245#[cfg(test)]
246mod tests {
247 use super::*;
248
249 #[test]
250 fn parses_known_mobile_and_console_targets() {
251 assert_eq!(
252 Target::from_str("aarch64_ios").unwrap(),
253 Target::new(TargetArchitecture::Aarch64, TargetOperatingSystem::IOS)
254 );
255 assert_eq!(
256 Target::from_str("aarch64_horizon").unwrap(),
257 Target::new(TargetArchitecture::Aarch64, TargetOperatingSystem::Horizon)
258 );
259 assert_eq!(
260 Target::from_str("arm32_vita").unwrap(),
261 Target::new(TargetArchitecture::Arm32, TargetOperatingSystem::Vita)
262 );
263 }
264
265 #[test]
266 fn displays_known_mobile_and_console_os_names() {
267 assert_eq!(TargetOperatingSystem::VisionOS.to_string(), "visionos");
268 assert_eq!(TargetOperatingSystem::Psp.to_string(), "psp");
269 assert_eq!(TargetOperatingSystem::Psx.to_string(), "psx");
270 }
271}