libcpuname 0.1.3

Identify CPU vendors, chips, and cores across multiple architectures
Documentation
use super::err::CoreNameError;
use super::Implementer;

// No authoritative source for this, so uses the following resources:
// - https://github.com/util-linux/util-linux/blob/master/sys-utils/lscpu-arm.c
// - https://github.com/gcc-mirror/gcc/blob/master/gcc/config/aarch64/aarch64-cores.def
// - https://github.com/phpsysinfo/phpsysinfo/blob/main/data/cpus.ini
pub const fn core_name(
    implementer: Implementer,
    part: u16,
    variant: u8,
) -> Result<&'static str, CoreNameError> {
    debug_assert!(part <= 0xFFF);
    debug_assert!(variant <= 0xF);

    match implementer {
        Implementer::Arm => arm_core_name(part),
        Implementer::Broadcom => broadcom_core_name(part),
        Implementer::Cavium => cavium_core_name(part),
        Implementer::Dec => dec_core_name(part),
        Implementer::Fujitsu => fujitsu_core_name(part),
        Implementer::Hisilicon => hisilicon_core_name(part),
        Implementer::Nvidia => nvidia_core_name(part),
        Implementer::Apm => apm_core_name(part, variant),
        Implementer::Qualcomm => qualcomm_core_name(part),
        Implementer::Samsung => samsung_core_name(part, variant),
        Implementer::TexasInstruments => ti_core_name(part),
        Implementer::Marvell => marvell_core_name(part),
        Implementer::Apple => apple_core_name(part),
        Implementer::Faraday => faraday_core_name(part),
        Implementer::Hxt => hxt_core_name(part),
        Implementer::Intel => intel_core_name(part),
        Implementer::Microsoft => microsoft_core_name(part),
        Implementer::Phytium => phytium_core_name(part),
        Implementer::Ampere => ampere_core_name(part),
        _ => Err(CoreNameError::NoKnownNamesForImplementer(implementer)),
    }
}

const fn arm_core_name(part: u16) -> Result<&'static str, CoreNameError> {
    match part {
        0x810 => Ok("ARM810"),
        0x920 => Ok("ARM920"),
        0x922 => Ok("ARM922"),
        0x926 => Ok("ARM926"),
        0x940 => Ok("ARM940"),
        0x946 => Ok("ARM946"),
        0x966 => Ok("ARM966"),
        0xA20 => Ok("ARM1020"),
        0xA22 => Ok("ARM1022"),
        0xA26 => Ok("ARM1026"),
        0xB02 => Ok("ARM11 MPCore"),
        0xB36 => Ok("ARM1136"),
        0xB56 => Ok("ARM1156"),
        0xB76 => Ok("ARM1176"),
        0xC05 => Ok("Cortex-A5"),
        0xC07 => Ok("Cortex-A7"),
        0xC08 => Ok("Cortex-A8"),
        0xC09 => Ok("Cortex-A9"),
        0xC0D => Ok("Cortex-A17"), // formerly A12
        0xC0E => Ok("Cortex-A17"),
        0xC0F => Ok("Cortex-A15"),
        0xC14 => Ok("Cortex-R4"),
        0xC15 => Ok("Cortex-R5"),
        0xC17 => Ok("Cortex-R7"),
        0xC18 => Ok("Cortex-R8"),
        0xC20 => Ok("Cortex-M0"),
        0xC21 => Ok("Cortex-M1"),
        0xC23 => Ok("Cortex-M3"),
        0xC24 => Ok("Cortex-M4"),
        0xC27 => Ok("Cortex-M7"),
        0xC60 => Ok("Cortex-M0+"),
        0xD01 => Ok("Cortex-A32"),
        0xD02 => Ok("Cortex-A34"),
        0xD03 => Ok("Cortex-A53"),
        0xD04 => Ok("Cortex-A35"),
        0xD05 => Ok("Cortex-A55"),
        0xD06 => Ok("Cortex-A65"),
        0xD07 => Ok("Cortex-A57"),
        0xD08 => Ok("Cortex-A72"),
        0xD09 => Ok("Cortex-A73"),
        0xD0A => Ok("Cortex-A75"),
        0xD0B => Ok("Cortex-A76"),
        0xD0C => Ok("Neoverse N1"),
        0xD0D => Ok("Cortex-A77"),
        0xD0E => Ok("Cortex-A76AE"),
        0xD13 => Ok("Cortex-R52"),
        0xD14 => Ok("Cortex-R82AE"),
        0xD15 => Ok("Cortex-R82"),
        0xD16 => Ok("Cortex-R52+"),
        0xD20 => Ok("Cortex-M23"),
        0xD21 => Ok("Cortex-M33"),
        0xD22 => Ok("Cortex-M55"),
        0xD23 => Ok("Cortex-M85"),
        0xD40 => Ok("Neoverse V1"),
        0xD41 => Ok("Cortex-A78"),
        0xD42 => Ok("Cortex-A78AE"),
        0xD43 => Ok("Cortex-A65AE"),
        0xD44 => Ok("Cortex-X1"),
        0xD46 => Ok("Cortex-A510"),
        0xD47 => Ok("Cortex-A710"),
        0xD48 => Ok("Cortex-X2"),
        0xD49 => Ok("Neoverse N2"),
        0xD4A => Ok("Neoverse E1"),
        0xD4B => Ok("Cortex-A78C"),
        0xD4C => Ok("Cortex-X1C"),
        0xD4D => Ok("Cortex-A715"),
        0xD4E => Ok("Cortex-X3"),
        0xD4F => Ok("Neoverse V2"),
        0xD80 => Ok("Cortex-A520"),
        0xD81 => Ok("Cortex-A720"),
        0xD82 => Ok("Cortex-X4"),
        0xD83 => Ok("Neoverse V3AE"),
        0xD84 => Ok("Neoverse V3"),
        0xD85 => Ok("Cortex-X925"),
        0xD87 => Ok("Cortex-A725"),
        0xD88 => Ok("Cortex-A520AE"),
        0xD89 => Ok("Cortex-A720AE"),
        0xD8E => Ok("Neoverse N3"),
        0xD8F => Ok("Cortex-A320"),
        _ => Err(CoreNameError::NoKnownNamesForPart(part)),
    }
}

const fn broadcom_core_name(part: u16) -> Result<&'static str, CoreNameError> {
    match part {
        0x00F => Ok("Brahma-B15"),
        0x100 => Ok("Brahma-B53"),
        0x516 => Ok("ThunderX2"),
        _ => Err(CoreNameError::NoKnownNamesForPart(part)),
    }
}

const fn cavium_core_name(part: u16) -> Result<&'static str, CoreNameError> {
    match part {
        0x0A0 => Ok("ThunderX"),
        0x0A1 => Ok("ThunderX T88"),
        0x0A2 => Ok("ThunderX T81"),
        0x0A3 => Ok("ThunderX T83"),
        0x0AF => Ok("ThunderX2 T99"),
        0x0B0 => Ok("OcteonTX2"),
        0x0B1 => Ok("OcteonTX2 98XX"),
        0x0B2 => Ok("OcteonTX2 96XX"),
        0x0B3 => Ok("OcteonTX2 95XX"),
        0x0B4 => Ok("OcteonTX2 95XXN"),
        0x0B5 => Ok("OcteonTX2 95XXMM"),
        0x0B6 => Ok("OcteonTX2 95XX0"),
        0x0B8 => Ok("ThunderX3 T110"),
        _ => Err(CoreNameError::NoKnownNamesForPart(part)),
    }
}

const fn dec_core_name(part: u16) -> Result<&'static str, CoreNameError> {
    match part {
        0xA10 => Ok("SA110"),
        0xA11 => Ok("SA1100"),
        _ => Err(CoreNameError::NoKnownNamesForPart(part)),
    }
}

const fn fujitsu_core_name(part: u16) -> Result<&'static str, CoreNameError> {
    match part {
        0x001 => Ok("A64FX"),
        0x003 => Ok("MONAKA"),
        _ => Err(CoreNameError::NoKnownNamesForPart(part)),
    }
}

const fn hisilicon_core_name(part: u16) -> Result<&'static str, CoreNameError> {
    match part {
        0xD01 => Ok("TaiShan V110"),
        0xD02 => Ok("TaiShan V120"),
        0xD03 => Ok("TaiShan V121"),
        0xD05 => Ok("TaiShan V121"),
        0xD40 => Ok("Cortex-A76"),
        0xD41 => Ok("Cortex-A77"),
        0xD42 => Ok("TaiShan V120"),
        _ => Err(CoreNameError::NoKnownNamesForPart(part)),
    }
}

const fn nvidia_core_name(part: u16) -> Result<&'static str, CoreNameError> {
    match part {
        0x000 => Ok("Denver"),
        0x003 => Ok("Denver 2"),
        0x004 => Ok("Carmel"),
        0x010 => Ok("Olympus"),
        _ => Err(CoreNameError::NoKnownNamesForPart(part)),
    }
}

const fn apm_core_name(part: u16, variant: u8) -> Result<&'static str, CoreNameError> {
    match part {
        0x000 => match variant {
            0x3.. => Ok("eMAG"),
            _ => Ok("X-Gene"),
        },
        _ => Err(CoreNameError::NoKnownNamesForPart(part)),
    }
}

const fn qualcomm_core_name(part: u16) -> Result<&'static str, CoreNameError> {
    match part {
        0x001 => Ok("Oryon"),
        0x00F => Ok("Scorpion"),
        0x02D => Ok("Scorpion"),
        0x04D => Ok("Krait"),
        0x06F => Ok("Krait"),
        0x201 => Ok("Kryo"),
        0x205 => Ok("Kryo"),
        0x211 => Ok("Kryo"),
        0x800 => Ok("Falkor-V1 / Kryo"),
        0x801 => Ok("Kryo V2"),
        0x802 => Ok("Kryo 3XX Gold"),
        0x803 => Ok("Kryo 3XX Silver"),
        0x804 => Ok("Kryo 4XX Gold"),
        0x805 => Ok("Kryo 4XX Silver / Kryo 5XX Silver"),
        0xC00 => Ok("Falkor"),
        0xC01 => Ok("Saphira"),
        _ => Err(CoreNameError::NoKnownNamesForPart(part)),
    }
}

const fn samsung_core_name(part: u16, variant: u8) -> Result<&'static str, CoreNameError> {
    match part {
        0x001 => match variant {
            0x1 => Ok("Exynos-M1"),
            0x4 => Ok("Exynos-M2"),
            _ => Ok("Exynos-M1/M2"),
        },
        0x002 => Ok("Exynos-M3"),
        0x003 => Ok("Exynos-M4"),
        0x004 => Ok("Exynos-M5"),
        _ => Err(CoreNameError::NoKnownNamesForPart(part)),
    }
}

const fn ti_core_name(part: u16) -> Result<&'static str, CoreNameError> {
    match part {
        0x925 => Ok("TI925"),
        _ => Err(CoreNameError::NoKnownNamesForPart(part)),
    }
}

const fn marvell_core_name(part: u16) -> Result<&'static str, CoreNameError> {
    match part {
        0x131 => Ok("Feroceon 88FR131"),
        0x581 => Ok("PJ4 / PJ4B"),
        0x584 => Ok("PJ4B-MP"),
        _ => Err(CoreNameError::NoKnownNamesForPart(part)),
    }
}

const fn apple_core_name(part: u16) -> Result<&'static str, CoreNameError> {
    match part {
        0x000 => Ok("Swift"),
        0x001 => Ok("Cyclone"),
        0x002 => Ok("Typhoon"),
        0x003 => Ok("Capri / Typhoon"),
        0x004 => Ok("Twister"),
        0x005 => Ok("Elba / Malta / Twister"),
        0x006 => Ok("Hurricane"),
        0x007 => Ok("Hurricane / Myst"),
        0x008 => Ok("Monsoon"),
        0x009 => Ok("Mistral"),
        0x00B => Ok("Vortex"),
        0x00C => Ok("Tempest"),
        0x00F => Ok("Tempest-M9"),
        0x010 => Ok("Aruba / Vortex"),
        0x011 => Ok("Aruba / Tempest"),
        0x012 => Ok("Lightning"),
        0x013 => Ok("Thunder"),
        0x020 => Ok("Icestorm (A14)"),
        0x021 => Ok("Firestorm (A14)"),
        0x022 => Ok("Icestorm (M1)"),
        0x023 => Ok("Firestorm (M1)"),
        0x024 => Ok("Icestorm (M1 Pro)"),
        0x025 => Ok("Firestorm (M1 Pro)"),
        0x026 => Ok("Thunder (M10)"),
        0x028 => Ok("Icestorm (M1 Max)"),
        0x029 => Ok("Firestorm (M1 Max)"),
        0x030 => Ok("Blizzard (A15)"),
        0x031 => Ok("Avalanche (A15)"),
        0x032 => Ok("Blizzard (M2)"),
        0x033 => Ok("Avalanche (M2)"),
        0x034 => Ok("Blizzard (M2 Pro)"),
        0x035 => Ok("Avalanche (M2 Pro)"),
        0x036 => Ok("Sawtooth (A16)"),
        0x037 => Ok("Everest (A16)"),
        0x038 => Ok("Blizzard (M2 Max)"),
        0x039 => Ok("Avalanche (M2 Max)"),
        0x048 => Ok("Ibiza-E"),
        0x049 => Ok("Ibiza-P"),
        _ => Err(CoreNameError::NoKnownNamesForPart(part)),
    }
}

const fn faraday_core_name(part: u16) -> Result<&'static str, CoreNameError> {
    match part {
        0x526 => Ok("FA526"),
        0x626 => Ok("FA626"),
        _ => Err(CoreNameError::NoKnownNamesForPart(part)),
    }
}

const fn hxt_core_name(part: u16) -> Result<&'static str, CoreNameError> {
    match part {
        0x000 => Ok("Phecda"),
        _ => Err(CoreNameError::NoKnownNamesForPart(part)),
    }
}

const fn intel_core_name(part: u16) -> Result<&'static str, CoreNameError> {
    match part {
        0x200 => Ok("i80200"),
        0x210 => Ok("PXA250A"),
        0x212 => Ok("PXA210A"),
        0x242 => Ok("i80321-400"),
        0x243 => Ok("i80321-600"),
        0x290 => Ok("PXA250B / PXA26x"),
        0x292 => Ok("PXA210B"),
        0x2C2 => Ok("i80321-400-B0"),
        0x2C3 => Ok("i80321-600-B0"),
        0x2D0 => Ok("PXA250C / PXA255 / PXA26x"),
        0x2D2 => Ok("PXA210C"),
        0x411 => Ok("PXA27x"),
        0x41C => Ok("IPX425-533"),
        0x41D => Ok("IPX425-400"),
        0x41F => Ok("IPX425-266"),
        0x682 => Ok("PXA32x"),
        0x683 => Ok("PXA930 / PXA935"),
        0x688 => Ok("PXA30x"),
        0x689 => Ok("PXA31x"),
        0xB11 => Ok("SA1110"),
        0xC12 => Ok("IPX1200"),
        _ => Err(CoreNameError::NoKnownNamesForPart(part)),
    }
}

const fn microsoft_core_name(part: u16) -> Result<&'static str, CoreNameError> {
    match part {
        0xD49 => Ok("Azure Cobalt 100"),
        _ => Err(CoreNameError::NoKnownNamesForPart(part)),
    }
}

const fn phytium_core_name(part: u16) -> Result<&'static str, CoreNameError> {
    match part {
        0x303 => Ok("FTC310"),
        0x660 => Ok("FTC660"),
        0x661 => Ok("FTC661"),
        0x662 => Ok("FTC662"),
        0x663 => Ok("FTC663"),
        0x664 => Ok("FTC664"),
        0x862 => Ok("FTC862"),
        _ => Err(CoreNameError::NoKnownNamesForPart(part)),
    }
}

const fn ampere_core_name(part: u16) -> Result<&'static str, CoreNameError> {
    match part {
        0xAC3 => Ok("Ampere-1"),
        0xAC4 => Ok("Ampere-1A"),
        0xAC5 => Ok("Ampere-1B"),
        _ => Err(CoreNameError::NoKnownNamesForPart(part)),
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use strum::IntoEnumIterator;

    #[test]
    #[should_panic]
    fn invalid_part() {
        let _ = core_name(Implementer::Arm, 0xFFFF, 0x0);
    }

    #[test]
    fn no_matches_for_implementer() {
        assert!(core_name(Implementer::MotorolaOrFreescale, 0x0, 0x0).is_err())
    }

    #[test]
    fn valid_inputs_never_panic() {
        Implementer::iter().for_each(|implementer| {
            for family in 0..=0xFFF {
                for model in 0..=0xF {
                    let _ = core_name(implementer, family, model);
                }
            }
        });
    }
}