use crate::platform::Caps;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
#[non_exhaustive]
pub enum Crc24Force {
#[default]
Auto,
Reference,
Portable,
Clmul,
}
impl Crc24Force {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Auto => "auto",
Self::Reference => "reference",
Self::Portable => "portable",
Self::Clmul => "clmul",
}
}
}
#[cfg(feature = "std")]
fn parse_force_env() -> Crc24Force {
let Ok(value) = std::env::var("RSCRYPTO_CRC24_FORCE") else {
return Crc24Force::Auto;
};
let value = value.trim();
if value.is_empty() {
return Crc24Force::Auto;
}
if value.eq_ignore_ascii_case("auto") {
return Crc24Force::Auto;
}
if value.eq_ignore_ascii_case("reference") || value.eq_ignore_ascii_case("bitwise") {
return Crc24Force::Reference;
}
if value.eq_ignore_ascii_case("portable")
|| value.eq_ignore_ascii_case("scalar")
|| value.eq_ignore_ascii_case("table")
{
return Crc24Force::Portable;
}
if value.eq_ignore_ascii_case("clmul")
|| value.eq_ignore_ascii_case("pclmul")
|| value.eq_ignore_ascii_case("pmull")
|| value.eq_ignore_ascii_case("vpmsum")
|| value.eq_ignore_ascii_case("vgfm")
|| value.eq_ignore_ascii_case("zbc")
|| value.eq_ignore_ascii_case("zvbc")
{
return Crc24Force::Clmul;
}
if value.eq_ignore_ascii_case("slice8") {
return Crc24Force::Portable;
}
if value.eq_ignore_ascii_case("slice4") {
return Crc24Force::Portable;
}
Crc24Force::Auto
}
#[inline]
#[must_use]
#[allow(unused_variables)]
fn clamp_force_to_caps(requested: Crc24Force, caps: Caps) -> Crc24Force {
match requested {
Crc24Force::Auto | Crc24Force::Reference | Crc24Force::Portable => requested,
Crc24Force::Clmul => {
#[cfg(target_arch = "x86_64")]
{
if caps.has(crate::platform::caps::x86::PCLMUL_READY) {
return Crc24Force::Clmul;
}
}
#[cfg(target_arch = "aarch64")]
{
if caps.has(crate::platform::caps::aarch64::PMULL_READY) {
return Crc24Force::Clmul;
}
}
#[cfg(target_arch = "powerpc64")]
{
if caps.has(crate::platform::caps::power::VPMSUM_READY) {
return Crc24Force::Clmul;
}
}
#[cfg(target_arch = "s390x")]
{
if caps.has(crate::platform::caps::s390x::VECTOR) {
return Crc24Force::Clmul;
}
}
#[cfg(target_arch = "riscv64")]
{
use crate::platform::caps::riscv;
if caps.has(riscv::ZBC) || caps.has(riscv::ZVBC) {
return Crc24Force::Clmul;
}
}
Crc24Force::Auto
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Crc24Config {
pub requested_force: Crc24Force,
pub effective_force: Crc24Force,
}
#[inline]
#[must_use]
fn config(caps: Caps) -> Crc24Config {
#[cfg(feature = "std")]
let requested_force = parse_force_env();
#[cfg(not(feature = "std"))]
let requested_force = Crc24Force::Auto;
let effective_force = clamp_force_to_caps(requested_force, caps);
Crc24Config {
requested_force,
effective_force,
}
}
#[inline]
#[must_use]
pub fn get() -> Crc24Config {
#[cfg(feature = "std")]
{
use std::sync::OnceLock;
static CACHED: OnceLock<Crc24Config> = OnceLock::new();
*CACHED.get_or_init(|| config(crate::platform::caps()))
}
#[cfg(not(feature = "std"))]
{
config(crate::platform::caps())
}
}