use err::{CoreNameError, TryFromIntError};
mod cores;
pub mod err;
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, Debug)]
#[cfg_attr(test, derive(strum::EnumIter))]
#[non_exhaustive]
#[repr(u8)]
pub enum Implementer {
Arm = 0x41,
Broadcom = 0x42,
Cavium = 0x43,
Dec = 0x44,
Fujitsu = 0x46,
Hisilicon = 0x48,
Infineon = 0x49,
MotorolaOrFreescale = 0x4D,
Nvidia = 0x4E,
Apm = 0x50,
Qualcomm = 0x51,
Samsung = 0x53,
TexasInstruments = 0x54,
Marvell = 0x56,
Apple = 0x61,
Faraday = 0x66,
Hxt = 0x68,
Intel = 0x69,
Microsoft = 0x6D,
Phytium = 0x70,
Ampere = 0xC0,
}
impl core::fmt::Display for Implementer {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let s = match self {
Self::Arm => "ARM",
Self::Broadcom => "Broadcom",
Self::Cavium => "Cavium",
Self::Dec => "DEC",
Self::Fujitsu => "Fujitsu",
Self::Hisilicon => "HiSilicon",
Self::Infineon => "Infineon",
Self::MotorolaOrFreescale => "Motorola/Freescale",
Self::Nvidia => "NVIDIA",
Self::Apm => "APM",
Self::Qualcomm => "Qualcomm",
Self::Samsung => "Samsung",
Self::TexasInstruments => "Texas Instruments",
Self::Marvell => "Marvell",
Self::Apple => "Apple",
Self::Faraday => "Faraday",
Self::Hxt => "HXT",
Self::Intel => "Intel",
Self::Microsoft => "Microsoft",
Self::Phytium => "Phytium",
Self::Ampere => "Ampere",
};
write!(f, "{s}")
}
}
macro_rules! try_from_impl_for_implementer {
($t:tt) => {
impl TryFrom<$t> for Implementer {
type Error = TryFromIntError;
fn try_from(v: $t) -> Result<Self, Self::Error> {
#[allow(irrefutable_let_patterns)]
let v = if let Ok(vu8) = u8::try_from(v) {
vu8
} else {
return Err(TryFromIntError);
};
match v {
v if v == Implementer::Arm as u8 => Ok(Implementer::Arm),
v if v == Implementer::Broadcom as u8 => Ok(Implementer::Broadcom),
v if v == Implementer::Cavium as u8 => Ok(Implementer::Cavium),
v if v == Implementer::Dec as u8 => Ok(Implementer::Dec),
v if v == Implementer::Fujitsu as u8 => Ok(Implementer::Fujitsu),
v if v == Implementer::Hisilicon as u8 => Ok(Implementer::Hisilicon),
v if v == Implementer::Infineon as u8 => Ok(Implementer::Infineon),
v if v == Implementer::MotorolaOrFreescale as u8 => {
Ok(Implementer::MotorolaOrFreescale)
}
v if v == Implementer::Nvidia as u8 => Ok(Implementer::Nvidia),
v if v == Implementer::Apm as u8 => Ok(Implementer::Apm),
v if v == Implementer::Qualcomm as u8 => Ok(Implementer::Qualcomm),
v if v == Implementer::Samsung as u8 => Ok(Implementer::Samsung),
v if v == Implementer::TexasInstruments as u8 => {
Ok(Implementer::TexasInstruments)
}
v if v == Implementer::Marvell as u8 => Ok(Implementer::Marvell),
v if v == Implementer::Apple as u8 => Ok(Implementer::Apple),
v if v == Implementer::Faraday as u8 => Ok(Implementer::Faraday),
v if v == Implementer::Hxt as u8 => Ok(Implementer::Hxt),
v if v == Implementer::Intel as u8 => Ok(Implementer::Intel),
v if v == Implementer::Microsoft as u8 => Ok(Implementer::Microsoft),
v if v == Implementer::Phytium as u8 => Ok(Implementer::Phytium),
v if v == Implementer::Ampere as u8 => Ok(Implementer::Ampere),
_ => Err(TryFromIntError),
}
}
}
};
}
try_from_impl_for_implementer!(u8);
try_from_impl_for_implementer!(u16);
try_from_impl_for_implementer!(u32);
try_from_impl_for_implementer!(u64);
try_from_impl_for_implementer!(u128);
try_from_impl_for_implementer!(usize);
try_from_impl_for_implementer!(i8);
try_from_impl_for_implementer!(i16);
try_from_impl_for_implementer!(i32);
try_from_impl_for_implementer!(i64);
try_from_impl_for_implementer!(i128);
try_from_impl_for_implementer!(isize);
macro_rules! from_implementer_impl_for_int {
($t:tt) => {
impl From<Implementer> for $t {
fn from(value: Implementer) -> Self {
value as $t
}
}
};
}
from_implementer_impl_for_int!(u8);
from_implementer_impl_for_int!(u16);
from_implementer_impl_for_int!(u32);
from_implementer_impl_for_int!(u64);
from_implementer_impl_for_int!(u128);
from_implementer_impl_for_int!(usize);
from_implementer_impl_for_int!(i16);
from_implementer_impl_for_int!(i32);
from_implementer_impl_for_int!(i64);
from_implementer_impl_for_int!(i128);
from_implementer_impl_for_int!(isize);
pub const fn core_name(
implementer: Implementer,
part: u16,
variant: u8,
) -> Result<&'static str, CoreNameError> {
if part > 0xFFF {
return Err(CoreNameError::InvalidPart(part));
}
if variant > 0xF {
return Err(CoreNameError::InvalidVariant(variant));
}
cores::core_name(implementer, part, variant)
}
#[cfg(test)]
mod tests {
use super::*;
use strum::IntoEnumIterator;
#[test]
fn implementer_typeconv() {
Implementer::iter().for_each(|it| {
let converted = u32::from(it).try_into();
assert!(converted.is_ok_and(|c: Implementer| c == it));
});
assert_eq!(Implementer::try_from(0xFF), Err(TryFromIntError));
assert_eq!(Implementer::try_from(0xFFFF), Err(TryFromIntError));
}
#[test]
fn implementer_display() {
assert!(Implementer::iter().all(|it| !it.to_string().is_empty()));
assert_eq!(Implementer::Arm.to_string(), "ARM");
}
#[test]
fn core_names() {
assert_eq!(
core_name(Implementer::Arm, 0xFFFF, 0x0),
Err(CoreNameError::InvalidPart(0xFFFF))
);
assert_eq!(
core_name(Implementer::Arm, 0x001, 0xFF),
Err(CoreNameError::InvalidVariant(0xFF))
);
assert_eq!(core_name(Implementer::Arm, 0xD07, 0x0), Ok("Cortex-A57"));
assert_eq!(core_name(Implementer::Apple, 0x006, 0x0), Ok("Hurricane"));
}
}