Skip to main content

lamina_platform/
target.rs

1//! Target architecture and operating system definitions.
2
3use 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    /// Detect the host system's target.
25    ///
26    /// # Examples
27    ///
28    /// ```
29    /// use lamina_platform::Target;
30    /// let host = Target::detect_host();
31    /// println!("Host target: {}", host);
32    /// ```
33    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}