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))]
54pub enum ArchError {
55 UnknownArchitecture,
57}
58
59impl fmt::Display for ArchError {
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 match self {
62 Self::UnknownArchitecture => write!(f, "unknown architecture"),
63 }
64 }
65}
66
67#[cfg(feature = "std")]
68impl std::error::Error for ArchError {}
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
98#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
99#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
100#[non_exhaustive]
101pub enum Arch {
102 X86,
104 X86_64,
106 AARCH64,
108 ARM,
110 RISCV32,
112 RISCV64,
114 WASM32,
116 WASM64,
118 MIPS,
120 MIPS64,
122 POWERPC,
124 POWERPC64,
126 S390X,
128}
129
130impl Arch {
131 #[must_use]
146 pub const fn current() -> Self {
147 #[cfg(target_arch = "x86")]
148 return Self::X86;
149 #[cfg(target_arch = "x86_64")]
150 return Self::X86_64;
151 #[cfg(target_arch = "aarch64")]
152 return Self::AARCH64;
153 #[cfg(target_arch = "arm")]
154 return Self::ARM;
155 #[cfg(target_arch = "riscv32")]
156 return Self::RISCV32;
157 #[cfg(target_arch = "riscv64")]
158 return Self::RISCV64;
159 #[cfg(target_arch = "wasm32")]
160 return Self::WASM32;
161 #[cfg(target_arch = "wasm64")]
162 return Self::WASM64;
163 #[cfg(target_arch = "mips")]
164 return Self::MIPS;
165 #[cfg(target_arch = "mips64")]
166 return Self::MIPS64;
167 #[cfg(target_arch = "powerpc")]
168 return Self::POWERPC;
169 #[cfg(target_arch = "powerpc64")]
170 return Self::POWERPC64;
171 #[cfg(target_arch = "s390x")]
172 return Self::S390X;
173 #[cfg(not(any(
174 target_arch = "x86",
175 target_arch = "x86_64",
176 target_arch = "aarch64",
177 target_arch = "arm",
178 target_arch = "riscv32",
179 target_arch = "riscv64",
180 target_arch = "wasm32",
181 target_arch = "wasm64",
182 target_arch = "mips",
183 target_arch = "mips64",
184 target_arch = "powerpc",
185 target_arch = "powerpc64",
186 target_arch = "s390x",
187 )))]
188 {
189 panic!("unsupported target architecture")
192 }
193 }
194
195 #[must_use]
207 pub const fn as_str(&self) -> &'static str {
208 match self {
209 Self::X86 => "x86",
210 Self::X86_64 => "x86_64",
211 Self::AARCH64 => "aarch64",
212 Self::ARM => "arm",
213 Self::RISCV32 => "riscv32",
214 Self::RISCV64 => "riscv64",
215 Self::WASM32 => "wasm32",
216 Self::WASM64 => "wasm64",
217 Self::MIPS => "mips",
218 Self::MIPS64 => "mips64",
219 Self::POWERPC => "powerpc",
220 Self::POWERPC64 => "powerpc64",
221 Self::S390X => "s390x",
222 }
223 }
224
225 #[must_use]
238 pub const fn is_64_bit(&self) -> bool {
239 matches!(
240 self,
241 Self::X86_64
242 | Self::AARCH64
243 | Self::RISCV64
244 | Self::WASM64
245 | Self::MIPS64
246 | Self::POWERPC64
247 | Self::S390X
248 )
249 }
250
251 #[must_use]
264 pub const fn is_32_bit(&self) -> bool {
265 matches!(
266 self,
267 Self::X86 | Self::ARM | Self::RISCV32 | Self::WASM32 | Self::MIPS | Self::POWERPC
268 )
269 }
270
271 #[must_use]
283 pub const fn is_arm(&self) -> bool {
284 matches!(self, Self::ARM | Self::AARCH64)
285 }
286
287 #[must_use]
299 pub const fn is_x86(&self) -> bool {
300 matches!(self, Self::X86 | Self::X86_64)
301 }
302
303 #[must_use]
315 pub const fn is_riscv(&self) -> bool {
316 matches!(self, Self::RISCV32 | Self::RISCV64)
317 }
318
319 #[must_use]
331 pub const fn is_wasm(&self) -> bool {
332 matches!(self, Self::WASM32 | Self::WASM64)
333 }
334
335 #[must_use]
347 pub const fn is_mips(&self) -> bool {
348 matches!(self, Self::MIPS | Self::MIPS64)
349 }
350
351 #[must_use]
363 pub const fn is_powerpc(&self) -> bool {
364 matches!(self, Self::POWERPC | Self::POWERPC64)
365 }
366
367 #[must_use]
379 pub const fn pointer_width(&self) -> u8 {
380 if self.is_64_bit() {
381 64
382 } else {
383 32
384 }
385 }
386}
387
388impl TryFrom<&str> for Arch {
389 type Error = ArchError;
390
391 fn try_from(s: &str) -> Result<Self, Self::Error> {
392 s.parse()
393 }
394}
395
396impl FromStr for Arch {
397 type Err = ArchError;
398
399 fn from_str(s: &str) -> Result<Self, Self::Err> {
400 match s.to_lowercase().as_str() {
401 "x86" | "i386" | "i486" | "i586" | "i686" => Ok(Self::X86),
402 "x86_64" | "amd64" | "x64" => Ok(Self::X86_64),
403 "aarch64" | "arm64" => Ok(Self::AARCH64),
404 "arm" => Ok(Self::ARM),
405 "riscv32" | "riscv-32" | "riscv_32" => Ok(Self::RISCV32),
406 "riscv64" | "riscv-64" | "riscv_64" => Ok(Self::RISCV64),
407 "wasm32" | "wasm-32" | "wasm_32" => Ok(Self::WASM32),
408 "wasm64" | "wasm-64" | "wasm_64" => Ok(Self::WASM64),
409 "mips" => Ok(Self::MIPS),
410 "mips64" => Ok(Self::MIPS64),
411 "powerpc" | "ppc" => Ok(Self::POWERPC),
412 "powerpc64" | "ppc64" => Ok(Self::POWERPC64),
413 "s390x" | "s390" => Ok(Self::S390X),
414 _ => Err(ArchError::UnknownArchitecture),
415 }
416 }
417}
418
419impl fmt::Display for Arch {
420 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
421 write!(f, "{}", self.as_str())
422 }
423}
424
425#[cfg(test)]
426mod tests {
427 use super::*;
428
429 #[test]
430 fn test_as_str() {
431 assert_eq!(Arch::X86.as_str(), "x86");
432 assert_eq!(Arch::X86_64.as_str(), "x86_64");
433 assert_eq!(Arch::AARCH64.as_str(), "aarch64");
434 assert_eq!(Arch::ARM.as_str(), "arm");
435 assert_eq!(Arch::RISCV32.as_str(), "riscv32");
436 assert_eq!(Arch::RISCV64.as_str(), "riscv64");
437 assert_eq!(Arch::WASM32.as_str(), "wasm32");
438 assert_eq!(Arch::WASM64.as_str(), "wasm64");
439 assert_eq!(Arch::MIPS.as_str(), "mips");
440 assert_eq!(Arch::MIPS64.as_str(), "mips64");
441 assert_eq!(Arch::POWERPC.as_str(), "powerpc");
442 assert_eq!(Arch::POWERPC64.as_str(), "powerpc64");
443 assert_eq!(Arch::S390X.as_str(), "s390x");
444 }
445
446 #[test]
447 fn test_is_64_bit() {
448 assert!(!Arch::X86.is_64_bit());
449 assert!(Arch::X86_64.is_64_bit());
450 assert!(Arch::AARCH64.is_64_bit());
451 assert!(!Arch::ARM.is_64_bit());
452 assert!(!Arch::RISCV32.is_64_bit());
453 assert!(Arch::RISCV64.is_64_bit());
454 assert!(!Arch::WASM32.is_64_bit());
455 assert!(Arch::WASM64.is_64_bit());
456 assert!(!Arch::MIPS.is_64_bit());
457 assert!(Arch::MIPS64.is_64_bit());
458 assert!(!Arch::POWERPC.is_64_bit());
459 assert!(Arch::POWERPC64.is_64_bit());
460 assert!(Arch::S390X.is_64_bit());
461 }
462
463 #[test]
464 fn test_is_32_bit() {
465 assert!(Arch::X86.is_32_bit());
466 assert!(!Arch::X86_64.is_32_bit());
467 assert!(!Arch::AARCH64.is_32_bit());
468 assert!(Arch::ARM.is_32_bit());
469 assert!(Arch::RISCV32.is_32_bit());
470 assert!(!Arch::RISCV64.is_32_bit());
471 assert!(Arch::WASM32.is_32_bit());
472 assert!(!Arch::WASM64.is_32_bit());
473 assert!(Arch::MIPS.is_32_bit());
474 assert!(!Arch::MIPS64.is_32_bit());
475 assert!(Arch::POWERPC.is_32_bit());
476 assert!(!Arch::POWERPC64.is_32_bit());
477 assert!(!Arch::S390X.is_32_bit());
478 }
479
480 #[test]
481 fn test_is_arm() {
482 assert!(!Arch::X86.is_arm());
483 assert!(!Arch::X86_64.is_arm());
484 assert!(Arch::AARCH64.is_arm());
485 assert!(Arch::ARM.is_arm());
486 }
487
488 #[test]
489 fn test_is_x86() {
490 assert!(Arch::X86.is_x86());
491 assert!(Arch::X86_64.is_x86());
492 assert!(!Arch::AARCH64.is_x86());
493 assert!(!Arch::ARM.is_x86());
494 }
495
496 #[test]
497 fn test_is_riscv() {
498 assert!(Arch::RISCV32.is_riscv());
499 assert!(Arch::RISCV64.is_riscv());
500 assert!(!Arch::X86_64.is_riscv());
501 }
502
503 #[test]
504 fn test_is_wasm() {
505 assert!(Arch::WASM32.is_wasm());
506 assert!(Arch::WASM64.is_wasm());
507 assert!(!Arch::X86_64.is_wasm());
508 }
509
510 #[test]
511 fn test_is_mips() {
512 assert!(Arch::MIPS.is_mips());
513 assert!(Arch::MIPS64.is_mips());
514 assert!(!Arch::X86_64.is_mips());
515 }
516
517 #[test]
518 fn test_is_powerpc() {
519 assert!(Arch::POWERPC.is_powerpc());
520 assert!(Arch::POWERPC64.is_powerpc());
521 assert!(!Arch::X86_64.is_powerpc());
522 }
523
524 #[test]
525 fn test_pointer_width() {
526 assert_eq!(Arch::X86.pointer_width(), 32);
527 assert_eq!(Arch::X86_64.pointer_width(), 64);
528 assert_eq!(Arch::AARCH64.pointer_width(), 64);
529 assert_eq!(Arch::ARM.pointer_width(), 32);
530 }
531
532 #[test]
533 fn test_from_str() {
534 assert_eq!("x86".parse::<Arch>().unwrap(), Arch::X86);
535 assert_eq!("x86_64".parse::<Arch>().unwrap(), Arch::X86_64);
536 assert_eq!("amd64".parse::<Arch>().unwrap(), Arch::X86_64);
537 assert_eq!("aarch64".parse::<Arch>().unwrap(), Arch::AARCH64);
538 assert_eq!("arm64".parse::<Arch>().unwrap(), Arch::AARCH64);
539 assert_eq!("arm".parse::<Arch>().unwrap(), Arch::ARM);
540 assert_eq!("riscv32".parse::<Arch>().unwrap(), Arch::RISCV32);
541 assert_eq!("riscv64".parse::<Arch>().unwrap(), Arch::RISCV64);
542 assert_eq!("wasm32".parse::<Arch>().unwrap(), Arch::WASM32);
543 assert_eq!("wasm64".parse::<Arch>().unwrap(), Arch::WASM64);
544 assert_eq!("mips".parse::<Arch>().unwrap(), Arch::MIPS);
545 assert_eq!("mips64".parse::<Arch>().unwrap(), Arch::MIPS64);
546 assert_eq!("powerpc".parse::<Arch>().unwrap(), Arch::POWERPC);
547 assert_eq!("ppc".parse::<Arch>().unwrap(), Arch::POWERPC);
548 assert_eq!("powerpc64".parse::<Arch>().unwrap(), Arch::POWERPC64);
549 assert_eq!("ppc64".parse::<Arch>().unwrap(), Arch::POWERPC64);
550 assert_eq!("s390x".parse::<Arch>().unwrap(), Arch::S390X);
551
552 assert_eq!("X86_64".parse::<Arch>().unwrap(), Arch::X86_64);
554 assert_eq!("AARCH64".parse::<Arch>().unwrap(), Arch::AARCH64);
555 }
556
557 #[test]
558 fn test_from_str_error() {
559 assert!("unknown".parse::<Arch>().is_err());
560 assert!("".parse::<Arch>().is_err());
561 }
562
563 #[test]
564 fn test_display() {
565 assert_eq!(format!("{}", Arch::X86_64), "x86_64");
566 assert_eq!(format!("{}", Arch::AARCH64), "aarch64");
567 assert_eq!(format!("{}", Arch::X86), "x86");
568 }
569
570 #[test]
571 fn test_current() {
572 let _arch = Arch::current();
574 }
575
576 #[test]
577 fn test_copy() {
578 let arch = Arch::X86_64;
579 let arch2 = arch;
580 assert_eq!(arch, arch2);
581 }
582
583 #[test]
584 fn test_clone() {
585 let arch = Arch::X86_64;
586 let arch2 = arch.clone();
587 assert_eq!(arch, arch2);
588 }
589
590 #[test]
591 fn test_equality() {
592 assert_eq!(Arch::X86_64, Arch::X86_64);
593 assert_ne!(Arch::X86_64, Arch::X86);
594 }
595
596 #[test]
597 fn test_ordering() {
598 assert!(Arch::X86 < Arch::X86_64);
599 assert!(Arch::AARCH64 < Arch::ARM); }
601}