libcpuname 0.1.3

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

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
/// Error type indicating a failure to find a matching [`Vendor`].
pub enum VendorError {
    /// The provided `mvendorid` contained a bank index that exceeds the maximum possible value of 33,554,432.
    InvalidBank(u32),
    /// The provided `mvendorid` contained an offset that exceeds the maximum possible value of 126.
    InvalidOffset(u8),
    /// The provided `mvendorid` contained a bank index with no known company names.
    UnknownBank(u32),
    /// The provided `mvendorid` contained an offset that did not match any companies within the included bank.
    UnknownOffset(u8),
}

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

impl core::fmt::Display for VendorError {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        match self {
            Self::InvalidBank(bank) => {
                write!(f, "provided mvendorid contains bank index {bank} which is greater than the maximum of {MAX_JEDEC_COMPANY_ID_BANK}")
            }
            Self::InvalidOffset(offset) => {
                write!(f, "provided mvendorid contains offset {offset} which is greater than the maximum of {MAX_JEDEC_COMPANY_ID_OFFSET}")
            }
            Self::UnknownBank(bank) => {
                write!(
                    f,
                    "provided mvendorid contains bank index {bank} with no known company names"
                )
            }
            Self::UnknownOffset(offset) => {
                write!(
                    f,
                    "provided mvendorid contains offset {offset} with no known company name"
                )
            }
        }
    }
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
/// Error type indicating a failure to find a matching CPU core name.
pub enum CoreNameError {
    /// The number represented by the lower N-1 bits of the provided `marchid` is zero, which is not permitted by the spec.
    ZeroedMarchid(u64),
    /// The provided `marchid` has its MSB set despite the provided vendor being non-commercial.
    MismatchedInput(Vendor, u64),
    /// The provided vendor has no known core names.
    NoKnownNamesForVendor(Vendor),
    /// The provided vendor is known, but the provided `marchid` has no known core names.
    NoKnownNamesForMarchid(u64),
}

#[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::ZeroedMarchid(marchid) => {
                write!(
                    f,
                    "the lower N-1 bits in the provided marchid {marchid:X} equal zero"
                )
            }
            Self::MismatchedInput(vendor, marchid) => {
                write!(f, "the provided vendor {vendor} and marchid {marchid:X} are not valid when paired")
            }
            Self::NoKnownNamesForVendor(vendor) => {
                write!(f, "provided vendor {vendor} has no known core names")
            }
            Self::NoKnownNamesForMarchid(marchid) => {
                write!(f, "provided marchid {marchid: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 [`VendorError`].
    Vendor(VendorError),
    /// 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::Vendor(e) => write!(f, "{e}"),
            Self::CoreName(e) => write!(f, "{e}"),
        }
    }
}

impl From<VendorError> for Error {
    fn from(value: VendorError) -> Self {
        Self::Vendor(value)
    }
}

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

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

    #[test]
    fn error_conversion() {
        assert_eq!(
            Error::from(VendorError::InvalidBank(u32::MAX)),
            Error::Vendor(VendorError::InvalidBank(u32::MAX))
        );
        assert_eq!(
            Error::from(CoreNameError::NoKnownNamesForMarchid(0xFF)),
            Error::CoreName(CoreNameError::NoKnownNamesForMarchid(0xFF))
        );
    }

    #[test]
    fn display() {
        let errors: &[Error] = &[
            VendorError::InvalidBank(u32::MAX).into(),
            VendorError::InvalidOffset(0xFF).into(),
            VendorError::UnknownBank(1).into(),
            VendorError::UnknownOffset(1).into(),
            CoreNameError::ZeroedMarchid(0).into(),
            CoreNameError::MismatchedInput(Vendor::NonCommercial, 1).into(),
            CoreNameError::NoKnownNamesForVendor(Vendor::NonCommercial).into(),
            CoreNameError::NoKnownNamesForMarchid(0xFFF).into(),
        ];

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