use core::fmt;
use core::str::FromStr;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "arbitrary")]
use arbitrary::Arbitrary;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[non_exhaustive]
pub enum ArchError {
UnknownArchitecture,
}
impl fmt::Display for ArchError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::UnknownArchitecture => write!(f, "unknown architecture"),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for ArchError {}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
#[non_exhaustive]
pub enum Arch {
X86,
X86_64,
AARCH64,
ARM,
RISCV32,
RISCV64,
WASM32,
WASM64,
MIPS,
MIPS64,
POWERPC,
POWERPC64,
S390X,
}
impl Arch {
#[must_use]
pub const fn current() -> Self {
#[cfg(target_arch = "x86")]
return Self::X86;
#[cfg(target_arch = "x86_64")]
return Self::X86_64;
#[cfg(target_arch = "aarch64")]
return Self::AARCH64;
#[cfg(target_arch = "arm")]
return Self::ARM;
#[cfg(target_arch = "riscv32")]
return Self::RISCV32;
#[cfg(target_arch = "riscv64")]
return Self::RISCV64;
#[cfg(target_arch = "wasm32")]
return Self::WASM32;
#[cfg(target_arch = "wasm64")]
return Self::WASM64;
#[cfg(target_arch = "mips")]
return Self::MIPS;
#[cfg(target_arch = "mips64")]
return Self::MIPS64;
#[cfg(target_arch = "powerpc")]
return Self::POWERPC;
#[cfg(target_arch = "powerpc64")]
return Self::POWERPC64;
#[cfg(target_arch = "s390x")]
return Self::S390X;
#[cfg(not(any(
target_arch = "x86",
target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "arm",
target_arch = "riscv32",
target_arch = "riscv64",
target_arch = "wasm32",
target_arch = "wasm64",
target_arch = "mips",
target_arch = "mips64",
target_arch = "powerpc",
target_arch = "powerpc64",
target_arch = "s390x",
)))]
{
panic!("unsupported target architecture")
}
}
#[must_use]
pub const fn as_str(&self) -> &'static str {
match self {
Self::X86 => "x86",
Self::X86_64 => "x86_64",
Self::AARCH64 => "aarch64",
Self::ARM => "arm",
Self::RISCV32 => "riscv32",
Self::RISCV64 => "riscv64",
Self::WASM32 => "wasm32",
Self::WASM64 => "wasm64",
Self::MIPS => "mips",
Self::MIPS64 => "mips64",
Self::POWERPC => "powerpc",
Self::POWERPC64 => "powerpc64",
Self::S390X => "s390x",
}
}
#[must_use]
pub const fn is_64_bit(&self) -> bool {
matches!(
self,
Self::X86_64
| Self::AARCH64
| Self::RISCV64
| Self::WASM64
| Self::MIPS64
| Self::POWERPC64
| Self::S390X
)
}
#[must_use]
pub const fn is_32_bit(&self) -> bool {
matches!(
self,
Self::X86 | Self::ARM | Self::RISCV32 | Self::WASM32 | Self::MIPS | Self::POWERPC
)
}
#[must_use]
pub const fn is_arm(&self) -> bool {
matches!(self, Self::ARM | Self::AARCH64)
}
#[must_use]
pub const fn is_x86(&self) -> bool {
matches!(self, Self::X86 | Self::X86_64)
}
#[must_use]
pub const fn is_riscv(&self) -> bool {
matches!(self, Self::RISCV32 | Self::RISCV64)
}
#[must_use]
pub const fn is_wasm(&self) -> bool {
matches!(self, Self::WASM32 | Self::WASM64)
}
#[must_use]
pub const fn is_mips(&self) -> bool {
matches!(self, Self::MIPS | Self::MIPS64)
}
#[must_use]
pub const fn is_powerpc(&self) -> bool {
matches!(self, Self::POWERPC | Self::POWERPC64)
}
#[must_use]
pub const fn pointer_width(&self) -> u8 {
if self.is_64_bit() { 64 } else { 32 }
}
}
impl TryFrom<&str> for Arch {
type Error = ArchError;
fn try_from(s: &str) -> Result<Self, Self::Error> {
s.parse()
}
}
impl FromStr for Arch {
type Err = ArchError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"x86" | "i386" | "i486" | "i586" | "i686" => Ok(Self::X86),
"x86_64" | "amd64" | "x64" => Ok(Self::X86_64),
"aarch64" | "arm64" => Ok(Self::AARCH64),
"arm" => Ok(Self::ARM),
"riscv32" | "riscv-32" | "riscv_32" => Ok(Self::RISCV32),
"riscv64" | "riscv-64" | "riscv_64" => Ok(Self::RISCV64),
"wasm32" | "wasm-32" | "wasm_32" => Ok(Self::WASM32),
"wasm64" | "wasm-64" | "wasm_64" => Ok(Self::WASM64),
"mips" => Ok(Self::MIPS),
"mips64" => Ok(Self::MIPS64),
"powerpc" | "ppc" => Ok(Self::POWERPC),
"powerpc64" | "ppc64" => Ok(Self::POWERPC64),
"s390x" | "s390" => Ok(Self::S390X),
_ => Err(ArchError::UnknownArchitecture),
}
}
}
impl fmt::Display for Arch {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_as_str() {
assert_eq!(Arch::X86.as_str(), "x86");
assert_eq!(Arch::X86_64.as_str(), "x86_64");
assert_eq!(Arch::AARCH64.as_str(), "aarch64");
assert_eq!(Arch::ARM.as_str(), "arm");
assert_eq!(Arch::RISCV32.as_str(), "riscv32");
assert_eq!(Arch::RISCV64.as_str(), "riscv64");
assert_eq!(Arch::WASM32.as_str(), "wasm32");
assert_eq!(Arch::WASM64.as_str(), "wasm64");
assert_eq!(Arch::MIPS.as_str(), "mips");
assert_eq!(Arch::MIPS64.as_str(), "mips64");
assert_eq!(Arch::POWERPC.as_str(), "powerpc");
assert_eq!(Arch::POWERPC64.as_str(), "powerpc64");
assert_eq!(Arch::S390X.as_str(), "s390x");
}
#[test]
fn test_is_64_bit() {
assert!(!Arch::X86.is_64_bit());
assert!(Arch::X86_64.is_64_bit());
assert!(Arch::AARCH64.is_64_bit());
assert!(!Arch::ARM.is_64_bit());
assert!(!Arch::RISCV32.is_64_bit());
assert!(Arch::RISCV64.is_64_bit());
assert!(!Arch::WASM32.is_64_bit());
assert!(Arch::WASM64.is_64_bit());
assert!(!Arch::MIPS.is_64_bit());
assert!(Arch::MIPS64.is_64_bit());
assert!(!Arch::POWERPC.is_64_bit());
assert!(Arch::POWERPC64.is_64_bit());
assert!(Arch::S390X.is_64_bit());
}
#[test]
fn test_is_32_bit() {
assert!(Arch::X86.is_32_bit());
assert!(!Arch::X86_64.is_32_bit());
assert!(!Arch::AARCH64.is_32_bit());
assert!(Arch::ARM.is_32_bit());
assert!(Arch::RISCV32.is_32_bit());
assert!(!Arch::RISCV64.is_32_bit());
assert!(Arch::WASM32.is_32_bit());
assert!(!Arch::WASM64.is_32_bit());
assert!(Arch::MIPS.is_32_bit());
assert!(!Arch::MIPS64.is_32_bit());
assert!(Arch::POWERPC.is_32_bit());
assert!(!Arch::POWERPC64.is_32_bit());
assert!(!Arch::S390X.is_32_bit());
}
#[test]
fn test_is_arm() {
assert!(!Arch::X86.is_arm());
assert!(!Arch::X86_64.is_arm());
assert!(Arch::AARCH64.is_arm());
assert!(Arch::ARM.is_arm());
}
#[test]
fn test_is_x86() {
assert!(Arch::X86.is_x86());
assert!(Arch::X86_64.is_x86());
assert!(!Arch::AARCH64.is_x86());
assert!(!Arch::ARM.is_x86());
}
#[test]
fn test_is_riscv() {
assert!(Arch::RISCV32.is_riscv());
assert!(Arch::RISCV64.is_riscv());
assert!(!Arch::X86_64.is_riscv());
}
#[test]
fn test_is_wasm() {
assert!(Arch::WASM32.is_wasm());
assert!(Arch::WASM64.is_wasm());
assert!(!Arch::X86_64.is_wasm());
}
#[test]
fn test_is_mips() {
assert!(Arch::MIPS.is_mips());
assert!(Arch::MIPS64.is_mips());
assert!(!Arch::X86_64.is_mips());
}
#[test]
fn test_is_powerpc() {
assert!(Arch::POWERPC.is_powerpc());
assert!(Arch::POWERPC64.is_powerpc());
assert!(!Arch::X86_64.is_powerpc());
}
#[test]
fn test_pointer_width() {
assert_eq!(Arch::X86.pointer_width(), 32);
assert_eq!(Arch::X86_64.pointer_width(), 64);
assert_eq!(Arch::AARCH64.pointer_width(), 64);
assert_eq!(Arch::ARM.pointer_width(), 32);
}
#[test]
fn test_from_str() {
assert_eq!("x86".parse::<Arch>().unwrap(), Arch::X86);
assert_eq!("x86_64".parse::<Arch>().unwrap(), Arch::X86_64);
assert_eq!("amd64".parse::<Arch>().unwrap(), Arch::X86_64);
assert_eq!("aarch64".parse::<Arch>().unwrap(), Arch::AARCH64);
assert_eq!("arm64".parse::<Arch>().unwrap(), Arch::AARCH64);
assert_eq!("arm".parse::<Arch>().unwrap(), Arch::ARM);
assert_eq!("riscv32".parse::<Arch>().unwrap(), Arch::RISCV32);
assert_eq!("riscv64".parse::<Arch>().unwrap(), Arch::RISCV64);
assert_eq!("wasm32".parse::<Arch>().unwrap(), Arch::WASM32);
assert_eq!("wasm64".parse::<Arch>().unwrap(), Arch::WASM64);
assert_eq!("mips".parse::<Arch>().unwrap(), Arch::MIPS);
assert_eq!("mips64".parse::<Arch>().unwrap(), Arch::MIPS64);
assert_eq!("powerpc".parse::<Arch>().unwrap(), Arch::POWERPC);
assert_eq!("ppc".parse::<Arch>().unwrap(), Arch::POWERPC);
assert_eq!("powerpc64".parse::<Arch>().unwrap(), Arch::POWERPC64);
assert_eq!("ppc64".parse::<Arch>().unwrap(), Arch::POWERPC64);
assert_eq!("s390x".parse::<Arch>().unwrap(), Arch::S390X);
assert_eq!("X86_64".parse::<Arch>().unwrap(), Arch::X86_64);
assert_eq!("AARCH64".parse::<Arch>().unwrap(), Arch::AARCH64);
}
#[test]
fn test_from_str_error() {
assert!("unknown".parse::<Arch>().is_err());
assert!("".parse::<Arch>().is_err());
}
#[test]
fn test_display() {
assert_eq!(format!("{}", Arch::X86_64), "x86_64");
assert_eq!(format!("{}", Arch::AARCH64), "aarch64");
assert_eq!(format!("{}", Arch::X86), "x86");
}
#[test]
fn test_current() {
let _arch = Arch::current();
}
#[test]
fn test_copy() {
let arch = Arch::X86_64;
let arch2 = arch;
assert_eq!(arch, arch2);
}
#[test]
fn test_clone() {
let arch = Arch::X86_64;
let arch2 = arch.clone();
assert_eq!(arch, arch2);
}
#[test]
fn test_equality() {
assert_eq!(Arch::X86_64, Arch::X86_64);
assert_ne!(Arch::X86_64, Arch::X86);
}
#[test]
fn test_ordering() {
assert!(Arch::X86 < Arch::X86_64);
assert!(Arch::AARCH64 < Arch::ARM); }
}