use crate::platform::Caps;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
#[non_exhaustive]
pub enum Crc64Force {
#[default]
Auto,
Reference,
Portable,
Pclmul,
Vpclmul,
Pmull,
PmullEor3,
Sve2Pmull,
Vpmsum,
Vgfm,
Zbc,
Zvbc,
}
impl Crc64Force {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Auto => "auto",
Self::Reference => "reference",
Self::Portable => "portable",
Self::Pclmul => "pclmul",
Self::Vpclmul => "vpclmul",
Self::Pmull => "pmull",
Self::PmullEor3 => "pmull-eor3",
Self::Sve2Pmull => "sve2-pmull",
Self::Vpmsum => "vpmsum",
Self::Vgfm => "vgfm",
Self::Zbc => "zbc",
Self::Zvbc => "zvbc",
}
}
}
#[cfg(feature = "std")]
fn parse_force_env() -> Crc64Force {
let Ok(value) = std::env::var("RSCRYPTO_CRC64_FORCE") else {
return Crc64Force::Auto;
};
let value = value.trim();
if value.is_empty() {
return Crc64Force::Auto;
}
if value.eq_ignore_ascii_case("auto") {
return Crc64Force::Auto;
}
if value.eq_ignore_ascii_case("reference") || value.eq_ignore_ascii_case("bitwise") {
return Crc64Force::Reference;
}
if value.eq_ignore_ascii_case("portable")
|| value.eq_ignore_ascii_case("scalar")
|| value.eq_ignore_ascii_case("table")
{
return Crc64Force::Portable;
}
if value.eq_ignore_ascii_case("pclmul") || value.eq_ignore_ascii_case("clmul") {
return Crc64Force::Pclmul;
}
if value.eq_ignore_ascii_case("vpclmul") {
return Crc64Force::Vpclmul;
}
if value.eq_ignore_ascii_case("pmull") || value.eq_ignore_ascii_case("pmull-neon") {
return Crc64Force::Pmull;
}
if value.eq_ignore_ascii_case("pmull-eor3")
|| value.eq_ignore_ascii_case("eor3")
|| value.eq_ignore_ascii_case("pmull-sha3")
{
return Crc64Force::PmullEor3;
}
if value.eq_ignore_ascii_case("sve2-pmull")
|| value.eq_ignore_ascii_case("pmull-sve2")
|| value.eq_ignore_ascii_case("sve2")
{
return Crc64Force::Sve2Pmull;
}
if value.eq_ignore_ascii_case("vpmsum") || value.eq_ignore_ascii_case("vpmsumd") {
return Crc64Force::Vpmsum;
}
if value.eq_ignore_ascii_case("vgfm") || value.eq_ignore_ascii_case("gfmsum") {
return Crc64Force::Vgfm;
}
if value.eq_ignore_ascii_case("zbc") {
return Crc64Force::Zbc;
}
if value.eq_ignore_ascii_case("zvbc") || value.eq_ignore_ascii_case("vclmul") {
return Crc64Force::Zvbc;
}
Crc64Force::Auto
}
#[inline]
#[must_use]
#[allow(unused_variables)] fn clamp_force_to_caps(requested: Crc64Force, caps: Caps) -> Crc64Force {
match requested {
Crc64Force::Auto | Crc64Force::Reference | Crc64Force::Portable => requested,
Crc64Force::Pclmul => {
#[cfg(target_arch = "x86_64")]
{
if caps.has(crate::platform::caps::x86::PCLMUL_READY) {
return Crc64Force::Pclmul;
}
}
Crc64Force::Auto
}
Crc64Force::Vpclmul => {
#[cfg(target_arch = "x86_64")]
{
if caps.has(crate::platform::caps::x86::VPCLMUL_READY) {
return Crc64Force::Vpclmul;
}
}
Crc64Force::Auto
}
Crc64Force::Pmull => {
#[cfg(target_arch = "aarch64")]
{
if caps.has(crate::platform::caps::aarch64::PMULL_READY) {
return Crc64Force::Pmull;
}
}
Crc64Force::Auto
}
Crc64Force::PmullEor3 => {
#[cfg(target_arch = "aarch64")]
{
if caps.has(crate::platform::caps::aarch64::PMULL_EOR3_READY) {
return Crc64Force::PmullEor3;
}
}
Crc64Force::Auto
}
Crc64Force::Sve2Pmull => {
#[cfg(target_arch = "aarch64")]
{
if caps.has(crate::platform::caps::aarch64::SVE2_PMULL) && caps.has(crate::platform::caps::aarch64::PMULL_READY)
{
return Crc64Force::Sve2Pmull;
}
}
Crc64Force::Auto
}
Crc64Force::Vpmsum => {
#[cfg(target_arch = "powerpc64")]
{
if caps.has(crate::platform::caps::power::VPMSUM_READY) {
return Crc64Force::Vpmsum;
}
}
Crc64Force::Auto
}
Crc64Force::Vgfm => {
#[cfg(target_arch = "s390x")]
{
if caps.has(crate::platform::caps::s390x::VECTOR) {
return Crc64Force::Vgfm;
}
}
Crc64Force::Auto
}
Crc64Force::Zbc => {
#[cfg(target_arch = "riscv64")]
{
if caps.has(crate::platform::caps::riscv::ZBC) {
return Crc64Force::Zbc;
}
}
Crc64Force::Auto
}
Crc64Force::Zvbc => {
#[cfg(target_arch = "riscv64")]
{
if caps.has(crate::platform::caps::riscv::ZVBC) {
return Crc64Force::Zvbc;
}
}
Crc64Force::Auto
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Crc64Config {
pub requested_force: Crc64Force,
pub effective_force: Crc64Force,
}
#[inline]
#[must_use]
fn config(caps: Caps) -> Crc64Config {
#[cfg(feature = "std")]
let requested_force = parse_force_env();
#[cfg(not(feature = "std"))]
let requested_force = Crc64Force::Auto;
let effective_force = clamp_force_to_caps(requested_force, caps);
Crc64Config {
requested_force,
effective_force,
}
}
#[inline]
#[must_use]
pub fn get() -> Crc64Config {
#[cfg(feature = "std")]
{
use std::sync::OnceLock;
static CACHED: OnceLock<Crc64Config> = OnceLock::new();
*CACHED.get_or_init(|| config(crate::platform::caps()))
}
#[cfg(not(feature = "std"))]
{
config(crate::platform::caps())
}
}