use core::fmt;
use core::marker::PhantomData;
#[doc(inline)]
pub use crate::intel_features as features;
pub trait Features<G>: Copy + Sized {
fn query(runtime: &RuntimeSupport) -> Option<Self>;
}
impl<G> Features<G> for () {
fn query(_support: &RuntimeSupport) -> Option<Self> {
Some(())
}
}
impl<G, H: Feature<G>, T: Features<G>> Features<G> for (H, T) {
fn query(support: &RuntimeSupport) -> Option<Self> {
Some((H::query(support)?, T::query(support)?))
}
}
pub trait Feature<G>: Features<G> {}
#[marker]
pub unsafe trait HasFeature<G, F: Feature<G>>: Features<G> {}
unsafe impl<G, F> HasFeature<G, F> for ()
where F: Feature<G> {}
unsafe impl<G, H, T> HasFeature<G, H> for (H, T)
where H: Feature<G>, T: Features<G> {}
unsafe impl<G, F, H, T> HasFeature<G, F> for (H, T)
where F: Feature<G>, H: Feature<G>, T: HasFeature<G, F> {}
pub struct FeatureSet<G, L: Features<G>> {
group: PhantomData<G>,
feats: PhantomData<L>,
}
impl<G, L: Features<G>> Clone for FeatureSet<G, L> {
fn clone(&self) -> Self {
*self
}
}
impl<G, L: Features<G>> Copy for FeatureSet<G, L> {}
impl<G, L: Features<G>> FeatureSet<G, L> {
pub const fn new(_proof: L) -> Self {
Self {
group: PhantomData,
feats: PhantomData,
}
}
}
impl<G, L: Features<G>> From<L> for FeatureSet<G, L> {
fn from(proof: L) -> Self {
Self::new(proof)
}
}
impl<G, L: Features<G> + Default> Default for FeatureSet<G, L> {
fn default() -> Self {
L::default().into()
}
}
impl<G, L: Features<G>> fmt::Debug for FeatureSet<G, L> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(core::any::type_name_of_val(self))
}
}
pub enum EmptyGroup {}
#[doc(hidden)]
#[macro_export]
macro_rules! intel_features {
($head:ty $(, $tail:ty)* $(,)?) => {
($head, $crate::intel_features!($($tail),*))
};
() => { () };
}
pub struct RuntimeSupport {
sse: bool,
sse2: bool,
sse3: bool,
ssse3: bool,
sse4_1: bool,
sse4_2: bool,
avx: bool,
f16c: bool,
fma: bool,
avx2: bool,
}
impl RuntimeSupport {
pub fn detect() -> Self {
use raw_cpuid::CpuId;
let cpuid = CpuId::new();
let feats = cpuid.get_feature_info();
let feats = feats.as_ref();
let efeats = cpuid.get_extended_feature_info();
let efeats = efeats.as_ref();
Self {
sse: feats.is_some_and(|x| x.has_sse()),
sse2: feats.is_some_and(|x| x.has_sse2()),
sse3: feats.is_some_and(|x| x.has_sse3()),
ssse3: feats.is_some_and(|x| x.has_ssse3()),
sse4_1: feats.is_some_and(|x| x.has_sse41()),
sse4_2: feats.is_some_and(|x| x.has_sse42()),
avx: feats.is_some_and(|x| x.has_avx()),
f16c: feats.is_some_and(|x| x.has_f16c()),
fma: feats.is_some_and(|x| x.has_fma()),
avx2: efeats.is_some_and(|x| x.has_avx2()),
}
}
pub fn sse(&self) -> bool {
self.sse
}
pub fn sse2(&self) -> bool {
self.sse2
}
pub fn sse3(&self) -> bool {
self.sse3
}
pub fn ssse3(&self) -> bool {
self.ssse3
}
pub fn sse4_1(&self) -> bool {
self.sse4_1
}
pub fn sse4_2(&self) -> bool {
self.sse4_2
}
pub fn avx(&self) -> bool {
self.avx
}
pub fn f16c(&self) -> bool {
self.f16c
}
pub fn fma(&self) -> bool {
self.fma
}
pub fn avx2(&self) -> bool {
self.avx2
}
}