Skip to main content

bare_types/sys/
arch.rs

1//! CPU architecture type for system information.
2//!
3//! This module provides a type-safe abstraction for CPU architectures,
4//! ensuring valid architecture identifiers and providing convenient constants
5//! for common architectures.
6//!
7//! # Supported Architectures
8//!
9//! This type supports all major CPU architectures:
10//!
11//! - **x86**: 32-bit x86 (i386, i686)
12//! - **`x86_64`**: 64-bit x86 (amd64)
13//! - **aarch64**: 64-bit ARM (arm64)
14//! - **arm**: 32-bit ARM
15//! - **riscv32**: 32-bit RISC-V
16//! - **riscv64**: 64-bit RISC-V
17//! - **wasm32**: 32-bit WebAssembly
18//! - **wasm64**: 64-bit WebAssembly
19//! - **mips**: 32-bit MIPS
20//! - **mips64**: 64-bit MIPS
21//! - **powerpc**: 32-bit PowerPC
22//! - **powerpc64**: 64-bit PowerPC
23//! - **s390x**: IBM System/390
24//!
25//! # Examples
26//!
27//! ```rust
28//! use bare_types::sys::Arch;
29//!
30//! // Get current architecture (compile-time constant)
31//! let arch = Arch::current();
32//!
33//! // Check architecture properties
34//! assert!(arch.is_64_bit() || arch.is_32_bit());
35//!
36//! // Parse from string
37//! let arch: Arch = "x86_64".parse()?;
38//! assert_eq!(arch, Arch::X86_64);
39//! # Ok::<(), bare_types::sys::ArchError>(())
40//! ```
41
42use 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/// Error type for architecture parsing.
52#[derive(Debug, Clone, Copy, PartialEq, Eq)]
53#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
54pub enum ArchError {
55    /// Unknown architecture string
56    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/// CPU architecture type.
71///
72/// This enum provides type-safe CPU architecture identifiers.
73/// All variants are validated at construction time.
74///
75/// # Invariants
76///
77/// - All variants represent valid CPU architectures
78/// - Architecture information is determined at compile time
79///
80/// # Examples
81///
82/// ```rust
83/// use bare_types::sys::Arch;
84///
85/// // Use predefined constants
86/// let arch = Arch::X86_64;
87/// assert!(arch.is_64_bit());
88///
89/// // Get current architecture
90/// let current = Arch::current();
91/// println!("Running on: {}", current);
92///
93/// // Convert to string representation
94/// assert_eq!(Arch::AARCH64.as_str(), "aarch64");
95/// # Ok::<(), bare_types::sys::ArchError>(())
96/// ```
97#[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    /// 32-bit x86 architecture (i386, i686)
103    X86,
104    /// 64-bit x86 architecture (amd64)
105    X86_64,
106    /// 64-bit ARM architecture (arm64)
107    AARCH64,
108    /// 32-bit ARM architecture
109    ARM,
110    /// 32-bit RISC-V architecture
111    RISCV32,
112    /// 64-bit RISC-V architecture
113    RISCV64,
114    /// 32-bit WebAssembly
115    WASM32,
116    /// 64-bit WebAssembly
117    WASM64,
118    /// 32-bit MIPS architecture
119    MIPS,
120    /// 64-bit MIPS architecture
121    MIPS64,
122    /// 32-bit PowerPC architecture
123    POWERPC,
124    /// 64-bit PowerPC architecture
125    POWERPC64,
126    /// IBM System/390 architecture
127    S390X,
128}
129
130impl Arch {
131    /// Returns the current architecture (compile-time constant).
132    ///
133    /// This method returns the architecture the code was compiled for,
134    /// not necessarily the architecture of the host system (especially
135    /// relevant for cross-compilation).
136    ///
137    /// # Examples
138    ///
139    /// ```rust
140    /// use bare_types::sys::Arch;
141    ///
142    /// let arch = Arch::current();
143    /// println!("Compiled for: {}", arch);
144    /// ```
145    #[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            // For unknown architectures, we can't provide a constant
190            // This branch should ideally not be reached
191            panic!("unsupported target architecture")
192        }
193    }
194
195    /// Returns the string representation of this architecture.
196    ///
197    /// # Examples
198    ///
199    /// ```rust
200    /// use bare_types::sys::Arch;
201    ///
202    /// assert_eq!(Arch::X86_64.as_str(), "x86_64");
203    /// assert_eq!(Arch::AARCH64.as_str(), "aarch64");
204    /// assert_eq!(Arch::X86.as_str(), "x86");
205    /// ```
206    #[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    /// Returns `true` if this is a 64-bit architecture.
226    ///
227    /// # Examples
228    ///
229    /// ```rust
230    /// use bare_types::sys::Arch;
231    ///
232    /// assert!(Arch::X86_64.is_64_bit());
233    /// assert!(Arch::AARCH64.is_64_bit());
234    /// assert!(!Arch::X86.is_64_bit());
235    /// assert!(!Arch::ARM.is_64_bit());
236    /// ```
237    #[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    /// Returns `true` if this is a 32-bit architecture.
252    ///
253    /// # Examples
254    ///
255    /// ```rust
256    /// use bare_types::sys::Arch;
257    ///
258    /// assert!(Arch::X86.is_32_bit());
259    /// assert!(Arch::ARM.is_32_bit());
260    /// assert!(!Arch::X86_64.is_32_bit());
261    /// assert!(!Arch::AARCH64.is_32_bit());
262    /// ```
263    #[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    /// Returns `true` if this is an ARM architecture.
272    ///
273    /// # Examples
274    ///
275    /// ```rust
276    /// use bare_types::sys::Arch;
277    ///
278    /// assert!(Arch::AARCH64.is_arm());
279    /// assert!(Arch::ARM.is_arm());
280    /// assert!(!Arch::X86_64.is_arm());
281    /// ```
282    #[must_use]
283    pub const fn is_arm(&self) -> bool {
284        matches!(self, Self::ARM | Self::AARCH64)
285    }
286
287    /// Returns `true` if this is an x86 architecture.
288    ///
289    /// # Examples
290    ///
291    /// ```rust
292    /// use bare_types::sys::Arch;
293    ///
294    /// assert!(Arch::X86.is_x86());
295    /// assert!(Arch::X86_64.is_x86());
296    /// assert!(!Arch::AARCH64.is_x86());
297    /// ```
298    #[must_use]
299    pub const fn is_x86(&self) -> bool {
300        matches!(self, Self::X86 | Self::X86_64)
301    }
302
303    /// Returns `true` if this is a RISC-V architecture.
304    ///
305    /// # Examples
306    ///
307    /// ```rust
308    /// use bare_types::sys::Arch;
309    ///
310    /// assert!(Arch::RISCV32.is_riscv());
311    /// assert!(Arch::RISCV64.is_riscv());
312    /// assert!(!Arch::X86_64.is_riscv());
313    /// ```
314    #[must_use]
315    pub const fn is_riscv(&self) -> bool {
316        matches!(self, Self::RISCV32 | Self::RISCV64)
317    }
318
319    /// Returns `true` if this is a WebAssembly architecture.
320    ///
321    /// # Examples
322    ///
323    /// ```rust
324    /// use bare_types::sys::Arch;
325    ///
326    /// assert!(Arch::WASM32.is_wasm());
327    /// assert!(Arch::WASM64.is_wasm());
328    /// assert!(!Arch::X86_64.is_wasm());
329    /// ```
330    #[must_use]
331    pub const fn is_wasm(&self) -> bool {
332        matches!(self, Self::WASM32 | Self::WASM64)
333    }
334
335    /// Returns `true` if this is a MIPS architecture.
336    ///
337    /// # Examples
338    ///
339    /// ```rust
340    /// use bare_types::sys::Arch;
341    ///
342    /// assert!(Arch::MIPS.is_mips());
343    /// assert!(Arch::MIPS64.is_mips());
344    /// assert!(!Arch::X86_64.is_mips());
345    /// ```
346    #[must_use]
347    pub const fn is_mips(&self) -> bool {
348        matches!(self, Self::MIPS | Self::MIPS64)
349    }
350
351    /// Returns `true` if this is a PowerPC architecture.
352    ///
353    /// # Examples
354    ///
355    /// ```rust
356    /// use bare_types::sys::Arch;
357    ///
358    /// assert!(Arch::POWERPC.is_powerpc());
359    /// assert!(Arch::POWERPC64.is_powerpc());
360    /// assert!(!Arch::X86_64.is_powerpc());
361    /// ```
362    #[must_use]
363    pub const fn is_powerpc(&self) -> bool {
364        matches!(self, Self::POWERPC | Self::POWERPC64)
365    }
366
367    /// Returns the pointer width in bits for this architecture.
368    ///
369    /// # Examples
370    ///
371    /// ```rust
372    /// use bare_types::sys::Arch;
373    ///
374    /// assert_eq!(Arch::X86_64.pointer_width(), 64);
375    /// assert_eq!(Arch::X86.pointer_width(), 32);
376    /// assert_eq!(Arch::AARCH64.pointer_width(), 64);
377    /// ```
378    #[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        // Test case insensitivity
553        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        // Just verify it doesn't panic
573        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); // AARCH64 defined before ARM in enum
600    }
601}