libcpuname 0.1.3

Identify CPU vendors, chips, and cores across multiple architectures
Documentation
use super::Vendor;

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
/// Error type indicating a failure to convert a CPUID vendor string into a [`Vendor`].
pub enum ParseVendorError {
    /// The provided string's length does not match the required length of 12.
    InvalidLength(usize),
    /// The provided string contains non-ASCII characters.
    InvalidCharacters,
    /// The provided string is not a known CPUID vendor string.
    NoMatch([u8; 12]),
}

#[cfg(feature = "std")]
impl std::error::Error for ParseVendorError {}

impl core::fmt::Display for ParseVendorError {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        match self {
            Self::InvalidLength(len) => {
                write!(f, "provided string length {len} != 12")
            }
            Self::InvalidCharacters => {
                write!(f, "provided string contains non-ASCII characters")
            }
            Self::NoMatch(s) => write!(
                f,
                "no matching vendor found for provided bytes '{:?}'",
                s.as_slice()
            ),
        }
    }
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
/// Error type indicating a failure to find a matching CPU core name.
pub enum ChipNameError {
    /// The provided family exceeds the maximum possible value of `0x1E`.
    InvalidFamily(u8),
    /// The provided stepping exceeds the maximum possible value of `0xF`.
    InvalidStepping(u8),
    /// The provided vendor has no known chip names.
    NoKnownNamesForVendor(Vendor),
    /// The provided vendor is known, but the provided family has no known chip names.
    NoKnownNamesForFamily(u8),
    /// The provided vendor and family are both known, but the provided model has no known chip names.
    NoKnownNamesForModel(u8),
}

#[cfg(feature = "std")]
impl std::error::Error for ChipNameError {}

impl core::fmt::Display for ChipNameError {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        match self {
            Self::NoKnownNamesForVendor(vendor) => {
                write!(f, "no known chip names for provided vendor {vendor}")
            }
            Self::InvalidFamily(family) => write!(
                f,
                "provided family {family:X} is greater than the maximum of 0x1E"
            ),
            Self::InvalidStepping(stepping) => write!(
                f,
                "provided stepping {stepping:X} is greater than the maximum of 0xF"
            ),
            Self::NoKnownNamesForFamily(family) => {
                write!(f, "provided family {family:X} has no known chip names")
            }
            Self::NoKnownNamesForModel(model) => {
                write!(f, "provided model {model:X} has no known chip names")
            }
        }
    }
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
/// Error type indicating a failure to find a matching CPU core name.
pub enum CoreNameError {
    /// The provided family exceeds the maximum possible value of `0x1E`.
    InvalidFamily(u8),
    /// The provided vendor has no known chip names.
    NoKnownNamesForVendor(Vendor),
    /// The provided vendor is known, but the provided family has no known chip names.
    NoKnownNamesForFamily(u8),
    /// The provided vendor and family are both known, but the provided model has no known core names.
    NoKnownNamesForModel(u8),
}

#[cfg(feature = "std")]
impl std::error::Error for CoreNameError {}

impl core::fmt::Display for CoreNameError {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        match self {
            Self::NoKnownNamesForVendor(vendor) => {
                write!(f, "no known core names for provided vendor {vendor}")
            }
            Self::InvalidFamily(family) => write!(
                f,
                "provided family {family:X} is greater than the maximum of 0x1E"
            ),
            Self::NoKnownNamesForFamily(family) => {
                write!(f, "provided family {family:X} has no known core names")
            }
            Self::NoKnownNamesForModel(model) => {
                write!(f, "provided model {model:X} has no known core names")
            }
        }
    }
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
/// Composite error type representing all possible errors in this module.
pub enum Error {
    /// Wrapper for [`ParseVendorError`].
    ParseVendor(ParseVendorError),
    /// Wrapper for [`ChipNameError`].
    ChipName(ChipNameError),
    /// Wrapper for [`CoreNameError`].
    CoreName(CoreNameError),
}

#[cfg(feature = "std")]
impl std::error::Error for Error {}

impl core::fmt::Display for Error {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        match self {
            Self::ParseVendor(e) => write!(f, "{e}"),
            Self::ChipName(e) => write!(f, "{e}"),
            Self::CoreName(e) => write!(f, "{e}"),
        }
    }
}

impl From<ParseVendorError> for Error {
    fn from(err: ParseVendorError) -> Self {
        Self::ParseVendor(err)
    }
}

impl From<ChipNameError> for Error {
    fn from(err: ChipNameError) -> Self {
        Self::ChipName(err)
    }
}

impl From<CoreNameError> for Error {
    fn from(err: CoreNameError) -> Self {
        Self::CoreName(err)
    }
}

#[cfg(test)]
mod tests {
    use super::super::Vendor;
    use super::{ChipNameError, CoreNameError, Error, ParseVendorError};

    #[test]
    fn error_conversion() {
        assert_eq!(
            Error::from(ChipNameError::InvalidFamily(0xFF)),
            Error::ChipName(ChipNameError::InvalidFamily(0xFF))
        );
        assert_eq!(
            Error::from(CoreNameError::InvalidFamily(0xFF)),
            Error::CoreName(CoreNameError::InvalidFamily(0xFF))
        );
        assert_eq!(
            Error::from(ParseVendorError::InvalidCharacters),
            Error::ParseVendor(ParseVendorError::InvalidCharacters)
        );
    }

    #[test]
    fn display() {
        let errors: &[Error] = &[
            ChipNameError::InvalidFamily(0xFF).into(),
            ChipNameError::InvalidStepping(0xFF).into(),
            ChipNameError::NoKnownNamesForVendor(Vendor::Centaur).into(),
            ChipNameError::NoKnownNamesForFamily(0xFF).into(),
            ChipNameError::NoKnownNamesForModel(0xFF).into(),
            CoreNameError::InvalidFamily(0xFF).into(),
            CoreNameError::InvalidFamily(0xFF).into(),
            CoreNameError::NoKnownNamesForVendor(Vendor::Centaur).into(),
            CoreNameError::NoKnownNamesForFamily(0xFF).into(),
            CoreNameError::NoKnownNamesForModel(0xFF).into(),
            ParseVendorError::InvalidLength(0).into(),
            ParseVendorError::InvalidCharacters.into(),
            ParseVendorError::NoMatch([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).into(),
        ];

        assert!(errors.iter().all(|it| !it.to_string().is_empty()));
    }
}