1use core::fmt;
43use core::str::FromStr;
44
45#[cfg(feature = "serde")]
46use serde::{Deserialize, Serialize};
47
48#[cfg(feature = "arbitrary")]
49use arbitrary::Arbitrary;
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq)]
53#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
54#[non_exhaustive]
55pub enum ArchError {
56 UnknownArchitecture,
62}
63
64impl fmt::Display for ArchError {
65 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66 match self {
67 Self::UnknownArchitecture => write!(f, "unknown architecture"),
68 }
69 }
70}
71
72#[cfg(feature = "std")]
73impl std::error::Error for ArchError {}
74
75#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
103#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
104#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
105#[non_exhaustive]
106pub enum Arch {
107 X86,
109 X86_64,
111 AARCH64,
113 ARM,
115 RISCV32,
117 RISCV64,
119 WASM32,
121 WASM64,
123 MIPS,
125 MIPS64,
127 POWERPC,
129 POWERPC64,
131 S390X,
133}
134
135impl Arch {
136 #[must_use]
151 pub const fn current() -> Self {
152 #[cfg(target_arch = "x86")]
153 return Self::X86;
154 #[cfg(target_arch = "x86_64")]
155 return Self::X86_64;
156 #[cfg(target_arch = "aarch64")]
157 return Self::AARCH64;
158 #[cfg(target_arch = "arm")]
159 return Self::ARM;
160 #[cfg(target_arch = "riscv32")]
161 return Self::RISCV32;
162 #[cfg(target_arch = "riscv64")]
163 return Self::RISCV64;
164 #[cfg(target_arch = "wasm32")]
165 return Self::WASM32;
166 #[cfg(target_arch = "wasm64")]
167 return Self::WASM64;
168 #[cfg(target_arch = "mips")]
169 return Self::MIPS;
170 #[cfg(target_arch = "mips64")]
171 return Self::MIPS64;
172 #[cfg(target_arch = "powerpc")]
173 return Self::POWERPC;
174 #[cfg(target_arch = "powerpc64")]
175 return Self::POWERPC64;
176 #[cfg(target_arch = "s390x")]
177 return Self::S390X;
178 #[cfg(not(any(
179 target_arch = "x86",
180 target_arch = "x86_64",
181 target_arch = "aarch64",
182 target_arch = "arm",
183 target_arch = "riscv32",
184 target_arch = "riscv64",
185 target_arch = "wasm32",
186 target_arch = "wasm64",
187 target_arch = "mips",
188 target_arch = "mips64",
189 target_arch = "powerpc",
190 target_arch = "powerpc64",
191 target_arch = "s390x",
192 )))]
193 {
194 panic!("unsupported target architecture")
197 }
198 }
199
200 #[must_use]
212 pub const fn as_str(&self) -> &'static str {
213 match self {
214 Self::X86 => "x86",
215 Self::X86_64 => "x86_64",
216 Self::AARCH64 => "aarch64",
217 Self::ARM => "arm",
218 Self::RISCV32 => "riscv32",
219 Self::RISCV64 => "riscv64",
220 Self::WASM32 => "wasm32",
221 Self::WASM64 => "wasm64",
222 Self::MIPS => "mips",
223 Self::MIPS64 => "mips64",
224 Self::POWERPC => "powerpc",
225 Self::POWERPC64 => "powerpc64",
226 Self::S390X => "s390x",
227 }
228 }
229
230 #[must_use]
243 pub const fn is_64_bit(&self) -> bool {
244 matches!(
245 self,
246 Self::X86_64
247 | Self::AARCH64
248 | Self::RISCV64
249 | Self::WASM64
250 | Self::MIPS64
251 | Self::POWERPC64
252 | Self::S390X
253 )
254 }
255
256 #[must_use]
269 pub const fn is_32_bit(&self) -> bool {
270 matches!(
271 self,
272 Self::X86 | Self::ARM | Self::RISCV32 | Self::WASM32 | Self::MIPS | Self::POWERPC
273 )
274 }
275
276 #[must_use]
288 pub const fn is_arm(&self) -> bool {
289 matches!(self, Self::ARM | Self::AARCH64)
290 }
291
292 #[must_use]
304 pub const fn is_x86(&self) -> bool {
305 matches!(self, Self::X86 | Self::X86_64)
306 }
307
308 #[must_use]
320 pub const fn is_riscv(&self) -> bool {
321 matches!(self, Self::RISCV32 | Self::RISCV64)
322 }
323
324 #[must_use]
336 pub const fn is_wasm(&self) -> bool {
337 matches!(self, Self::WASM32 | Self::WASM64)
338 }
339
340 #[must_use]
352 pub const fn is_mips(&self) -> bool {
353 matches!(self, Self::MIPS | Self::MIPS64)
354 }
355
356 #[must_use]
368 pub const fn is_powerpc(&self) -> bool {
369 matches!(self, Self::POWERPC | Self::POWERPC64)
370 }
371
372 #[must_use]
384 pub const fn pointer_width(&self) -> u8 {
385 if self.is_64_bit() { 64 } else { 32 }
386 }
387}
388
389impl TryFrom<&str> for Arch {
390 type Error = ArchError;
391
392 fn try_from(s: &str) -> Result<Self, Self::Error> {
393 s.parse()
394 }
395}
396
397impl FromStr for Arch {
398 type Err = ArchError;
399
400 fn from_str(s: &str) -> Result<Self, Self::Err> {
401 match s.to_lowercase().as_str() {
402 "x86" | "i386" | "i486" | "i586" | "i686" => Ok(Self::X86),
403 "x86_64" | "amd64" | "x64" => Ok(Self::X86_64),
404 "aarch64" | "arm64" => Ok(Self::AARCH64),
405 "arm" => Ok(Self::ARM),
406 "riscv32" | "riscv-32" | "riscv_32" => Ok(Self::RISCV32),
407 "riscv64" | "riscv-64" | "riscv_64" => Ok(Self::RISCV64),
408 "wasm32" | "wasm-32" | "wasm_32" => Ok(Self::WASM32),
409 "wasm64" | "wasm-64" | "wasm_64" => Ok(Self::WASM64),
410 "mips" => Ok(Self::MIPS),
411 "mips64" => Ok(Self::MIPS64),
412 "powerpc" | "ppc" => Ok(Self::POWERPC),
413 "powerpc64" | "ppc64" => Ok(Self::POWERPC64),
414 "s390x" | "s390" => Ok(Self::S390X),
415 _ => Err(ArchError::UnknownArchitecture),
416 }
417 }
418}
419
420impl fmt::Display for Arch {
421 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
422 write!(f, "{}", self.as_str())
423 }
424}
425
426#[cfg(test)]
427mod tests {
428 use super::*;
429
430 #[test]
431 fn test_as_str() {
432 assert_eq!(Arch::X86.as_str(), "x86");
433 assert_eq!(Arch::X86_64.as_str(), "x86_64");
434 assert_eq!(Arch::AARCH64.as_str(), "aarch64");
435 assert_eq!(Arch::ARM.as_str(), "arm");
436 assert_eq!(Arch::RISCV32.as_str(), "riscv32");
437 assert_eq!(Arch::RISCV64.as_str(), "riscv64");
438 assert_eq!(Arch::WASM32.as_str(), "wasm32");
439 assert_eq!(Arch::WASM64.as_str(), "wasm64");
440 assert_eq!(Arch::MIPS.as_str(), "mips");
441 assert_eq!(Arch::MIPS64.as_str(), "mips64");
442 assert_eq!(Arch::POWERPC.as_str(), "powerpc");
443 assert_eq!(Arch::POWERPC64.as_str(), "powerpc64");
444 assert_eq!(Arch::S390X.as_str(), "s390x");
445 }
446
447 #[test]
448 fn test_is_64_bit() {
449 assert!(!Arch::X86.is_64_bit());
450 assert!(Arch::X86_64.is_64_bit());
451 assert!(Arch::AARCH64.is_64_bit());
452 assert!(!Arch::ARM.is_64_bit());
453 assert!(!Arch::RISCV32.is_64_bit());
454 assert!(Arch::RISCV64.is_64_bit());
455 assert!(!Arch::WASM32.is_64_bit());
456 assert!(Arch::WASM64.is_64_bit());
457 assert!(!Arch::MIPS.is_64_bit());
458 assert!(Arch::MIPS64.is_64_bit());
459 assert!(!Arch::POWERPC.is_64_bit());
460 assert!(Arch::POWERPC64.is_64_bit());
461 assert!(Arch::S390X.is_64_bit());
462 }
463
464 #[test]
465 fn test_is_32_bit() {
466 assert!(Arch::X86.is_32_bit());
467 assert!(!Arch::X86_64.is_32_bit());
468 assert!(!Arch::AARCH64.is_32_bit());
469 assert!(Arch::ARM.is_32_bit());
470 assert!(Arch::RISCV32.is_32_bit());
471 assert!(!Arch::RISCV64.is_32_bit());
472 assert!(Arch::WASM32.is_32_bit());
473 assert!(!Arch::WASM64.is_32_bit());
474 assert!(Arch::MIPS.is_32_bit());
475 assert!(!Arch::MIPS64.is_32_bit());
476 assert!(Arch::POWERPC.is_32_bit());
477 assert!(!Arch::POWERPC64.is_32_bit());
478 assert!(!Arch::S390X.is_32_bit());
479 }
480
481 #[test]
482 fn test_is_arm() {
483 assert!(!Arch::X86.is_arm());
484 assert!(!Arch::X86_64.is_arm());
485 assert!(Arch::AARCH64.is_arm());
486 assert!(Arch::ARM.is_arm());
487 }
488
489 #[test]
490 fn test_is_x86() {
491 assert!(Arch::X86.is_x86());
492 assert!(Arch::X86_64.is_x86());
493 assert!(!Arch::AARCH64.is_x86());
494 assert!(!Arch::ARM.is_x86());
495 }
496
497 #[test]
498 fn test_is_riscv() {
499 assert!(Arch::RISCV32.is_riscv());
500 assert!(Arch::RISCV64.is_riscv());
501 assert!(!Arch::X86_64.is_riscv());
502 }
503
504 #[test]
505 fn test_is_wasm() {
506 assert!(Arch::WASM32.is_wasm());
507 assert!(Arch::WASM64.is_wasm());
508 assert!(!Arch::X86_64.is_wasm());
509 }
510
511 #[test]
512 fn test_is_mips() {
513 assert!(Arch::MIPS.is_mips());
514 assert!(Arch::MIPS64.is_mips());
515 assert!(!Arch::X86_64.is_mips());
516 }
517
518 #[test]
519 fn test_is_powerpc() {
520 assert!(Arch::POWERPC.is_powerpc());
521 assert!(Arch::POWERPC64.is_powerpc());
522 assert!(!Arch::X86_64.is_powerpc());
523 }
524
525 #[test]
526 fn test_pointer_width() {
527 assert_eq!(Arch::X86.pointer_width(), 32);
528 assert_eq!(Arch::X86_64.pointer_width(), 64);
529 assert_eq!(Arch::AARCH64.pointer_width(), 64);
530 assert_eq!(Arch::ARM.pointer_width(), 32);
531 }
532
533 #[test]
534 fn test_from_str() {
535 assert_eq!("x86".parse::<Arch>().unwrap(), Arch::X86);
536 assert_eq!("x86_64".parse::<Arch>().unwrap(), Arch::X86_64);
537 assert_eq!("amd64".parse::<Arch>().unwrap(), Arch::X86_64);
538 assert_eq!("aarch64".parse::<Arch>().unwrap(), Arch::AARCH64);
539 assert_eq!("arm64".parse::<Arch>().unwrap(), Arch::AARCH64);
540 assert_eq!("arm".parse::<Arch>().unwrap(), Arch::ARM);
541 assert_eq!("riscv32".parse::<Arch>().unwrap(), Arch::RISCV32);
542 assert_eq!("riscv64".parse::<Arch>().unwrap(), Arch::RISCV64);
543 assert_eq!("wasm32".parse::<Arch>().unwrap(), Arch::WASM32);
544 assert_eq!("wasm64".parse::<Arch>().unwrap(), Arch::WASM64);
545 assert_eq!("mips".parse::<Arch>().unwrap(), Arch::MIPS);
546 assert_eq!("mips64".parse::<Arch>().unwrap(), Arch::MIPS64);
547 assert_eq!("powerpc".parse::<Arch>().unwrap(), Arch::POWERPC);
548 assert_eq!("ppc".parse::<Arch>().unwrap(), Arch::POWERPC);
549 assert_eq!("powerpc64".parse::<Arch>().unwrap(), Arch::POWERPC64);
550 assert_eq!("ppc64".parse::<Arch>().unwrap(), Arch::POWERPC64);
551 assert_eq!("s390x".parse::<Arch>().unwrap(), Arch::S390X);
552
553 assert_eq!("X86_64".parse::<Arch>().unwrap(), Arch::X86_64);
555 assert_eq!("AARCH64".parse::<Arch>().unwrap(), Arch::AARCH64);
556 }
557
558 #[test]
559 fn test_from_str_error() {
560 assert!("unknown".parse::<Arch>().is_err());
561 assert!("".parse::<Arch>().is_err());
562 }
563
564 #[test]
565 fn test_display() {
566 assert_eq!(format!("{}", Arch::X86_64), "x86_64");
567 assert_eq!(format!("{}", Arch::AARCH64), "aarch64");
568 assert_eq!(format!("{}", Arch::X86), "x86");
569 }
570
571 #[test]
572 fn test_current() {
573 let _arch = Arch::current();
575 }
576
577 #[test]
578 fn test_copy() {
579 let arch = Arch::X86_64;
580 let arch2 = arch;
581 assert_eq!(arch, arch2);
582 }
583
584 #[test]
585 fn test_clone() {
586 let arch = Arch::X86_64;
587 let arch2 = arch.clone();
588 assert_eq!(arch, arch2);
589 }
590
591 #[test]
592 fn test_equality() {
593 assert_eq!(Arch::X86_64, Arch::X86_64);
594 assert_ne!(Arch::X86_64, Arch::X86);
595 }
596
597 #[test]
598 fn test_ordering() {
599 assert!(Arch::X86 < Arch::X86_64);
600 assert!(Arch::AARCH64 < Arch::ARM); }
602}