use std::fmt;
use std::str::FromStr;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Target {
pub architecture: TargetArchitecture,
pub operating_system: TargetOperatingSystem,
}
impl Target {
pub fn new(architecture: TargetArchitecture, operating_system: TargetOperatingSystem) -> Self {
Self {
architecture,
operating_system,
}
}
pub fn to_str(&self) -> String {
format!("{}_{}", self.architecture, self.operating_system)
}
pub fn detect_host() -> Self {
use crate::detection::{detect_host_architecture_only, detect_host_os};
use std::str::FromStr;
let arch = detect_host_architecture_only();
let os = detect_host_os();
Self::new(
TargetArchitecture::from_str(arch).unwrap_or(TargetArchitecture::Unknown),
TargetOperatingSystem::from_str(os).unwrap_or(TargetOperatingSystem::Unknown),
)
}
}
impl FromStr for Target {
type Err = &'static str;
fn from_str(target: &str) -> Result<Self, Self::Err> {
let parts: Vec<&str> = target.rsplitn(2, '_').collect();
if parts.len() != 2 {
return Err("Invalid target format: expected 'architecture_os'");
}
Ok(Self::new(
TargetArchitecture::from_str(parts[1]).map_err(|_| "Invalid architecture")?,
TargetOperatingSystem::from_str(parts[0]).map_err(|_| "Invalid operating system")?,
))
}
}
impl fmt::Display for Target {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}_{}", self.architecture, self.operating_system)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TargetArchitecture {
X86_64,
Aarch64,
Arx64,
Arm32,
Riscv32,
Riscv64,
#[cfg(feature = "nightly")]
Riscv128,
Wasm32,
Wasm64,
PowerPC64,
#[cfg(feature = "nightly")]
Lisa,
Unknown,
}
impl FromStr for TargetArchitecture {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"x86_64" => Ok(Self::X86_64),
"aarch64" => Ok(Self::Aarch64),
"arx64" => Ok(Self::Arx64),
"arm32" => Ok(Self::Arm32),
"riscv32" => Ok(Self::Riscv32),
"riscv64" => Ok(Self::Riscv64),
#[cfg(feature = "nightly")]
"riscv128" => Ok(Self::Riscv128),
"wasm32" => Ok(Self::Wasm32),
"wasm64" => Ok(Self::Wasm64),
"wasm" => Ok(Self::Wasm32),
"ppc64" | "powerpc64" | "ppc64le" => Ok(Self::PowerPC64),
#[cfg(feature = "nightly")]
"lisa" => Ok(Self::Lisa),
_ => Err("Unknown architecture"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TargetOperatingSystem {
Linux,
MacOS,
Windows,
Android,
IOS,
TvOS,
WatchOS,
VisionOS,
FreeBSD,
OpenBSD,
NetBSD,
DragonFly,
Redox,
Horizon,
Psp,
Psx,
Vita,
#[cfg(feature = "nightly")]
Artery,
Unknown,
}
impl FromStr for TargetOperatingSystem {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"linux" => Ok(Self::Linux),
"macos" => Ok(Self::MacOS),
"windows" => Ok(Self::Windows),
"android" => Ok(Self::Android),
"ios" => Ok(Self::IOS),
"tvos" => Ok(Self::TvOS),
"watchos" => Ok(Self::WatchOS),
"visionos" => Ok(Self::VisionOS),
"freebsd" => Ok(Self::FreeBSD),
"openbsd" => Ok(Self::OpenBSD),
"netbsd" => Ok(Self::NetBSD),
"dragonfly" => Ok(Self::DragonFly),
"redox" => Ok(Self::Redox),
"horizon" => Ok(Self::Horizon),
"psp" => Ok(Self::Psp),
"psx" => Ok(Self::Psx),
"vita" => Ok(Self::Vita),
"unknown" => Ok(Self::Unknown),
#[cfg(feature = "nightly")]
"artery" => Ok(Self::Artery),
"bsd" => Ok(Self::FreeBSD),
_ => Err("Unknown operating system"),
}
}
}
impl fmt::Display for TargetArchitecture {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match self {
Self::X86_64 => "x86_64",
Self::Aarch64 => "aarch64",
Self::Arx64 => "arx64",
Self::Arm32 => "arm32",
Self::Riscv32 => "riscv32",
Self::Riscv64 => "riscv64",
#[cfg(feature = "nightly")]
Self::Riscv128 => "riscv128",
Self::Wasm32 => "wasm32",
Self::Wasm64 => "wasm64",
Self::PowerPC64 => "ppc64le",
#[cfg(feature = "nightly")]
Self::Lisa => "lisa",
Self::Unknown => "unknown",
};
write!(f, "{}", s)
}
}
impl fmt::Display for TargetOperatingSystem {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match self {
Self::Linux => "linux",
Self::MacOS => "macos",
Self::Windows => "windows",
Self::Android => "android",
Self::IOS => "ios",
Self::TvOS => "tvos",
Self::WatchOS => "watchos",
Self::VisionOS => "visionos",
Self::FreeBSD => "freebsd",
Self::OpenBSD => "openbsd",
Self::NetBSD => "netbsd",
Self::DragonFly => "dragonfly",
Self::Redox => "redox",
Self::Horizon => "horizon",
Self::Psp => "psp",
Self::Psx => "psx",
Self::Vita => "vita",
#[cfg(feature = "nightly")]
Self::Artery => "artery",
Self::Unknown => "unknown",
};
write!(f, "{}", s)
}
}
pub const HOST_ARCH_LIST: &[&str] = &[
"x86_64_unknown",
"x86_64_linux",
"x86_64_windows",
"x86_64_macos",
"x86_64_android",
"x86_64_ios",
"x86_64_tvos",
"x86_64_watchos",
"aarch64_unknown",
"aarch64_macos",
"aarch64_linux",
"aarch64_windows",
"aarch64_android",
"aarch64_ios",
"aarch64_tvos",
"aarch64_watchos",
"aarch64_visionos",
"aarch64_horizon",
"arm32_android",
"arm32_ios",
"arm32_watchos",
"arm32_vita",
"arx64_unknown",
"wasm32_unknown",
"wasm64_unknown",
"riscv32_unknown",
"riscv64_unknown",
#[cfg(feature = "nightly")]
"riscv128_unknown",
];
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_known_mobile_and_console_targets() {
assert_eq!(
Target::from_str("aarch64_ios").unwrap(),
Target::new(TargetArchitecture::Aarch64, TargetOperatingSystem::IOS)
);
assert_eq!(
Target::from_str("aarch64_horizon").unwrap(),
Target::new(TargetArchitecture::Aarch64, TargetOperatingSystem::Horizon)
);
assert_eq!(
Target::from_str("arm32_vita").unwrap(),
Target::new(TargetArchitecture::Arm32, TargetOperatingSystem::Vita)
);
}
#[test]
fn displays_known_mobile_and_console_os_names() {
assert_eq!(TargetOperatingSystem::VisionOS.to_string(), "visionos");
assert_eq!(TargetOperatingSystem::Psp.to_string(), "psp");
assert_eq!(TargetOperatingSystem::Psx.to_string(), "psx");
}
}