use crate::backend::Backend;
#[derive(Clone, Copy)]
pub struct Selection {
#[cfg_attr(not(feature = "std"), allow(dead_code))]
override_var: &'static str,
supported: &'static [Backend],
}
impl Selection {
#[must_use]
pub const fn new(override_var: &'static str) -> Self {
Selection {
override_var,
supported: &[],
}
}
#[must_use]
pub const fn supports(mut self, supported: &'static [Backend]) -> Self {
self.supported = supported;
self
}
#[must_use]
pub fn resolve(self) -> Backend {
#[cfg(feature = "std")]
{
let requested = std::env::var(self.override_var)
.ok()
.and_then(|value| Backend::from_name(value.trim()));
let on_host = Backend::probes_on_host;
let detected = detect(self.supported, on_host);
apply_override(self.supported, detected, requested, on_host)
}
#[cfg(not(feature = "std"))]
{
let _ = self;
Backend::Scalar
}
}
}
#[cfg(any(feature = "std", feature = "internals"))]
fn detect(supported: &[Backend], on_host: impl Fn(Backend) -> bool) -> Backend {
supported
.iter()
.copied()
.filter(|&backend| on_host(backend))
.min()
.unwrap_or(Backend::Scalar)
}
#[cfg(any(feature = "std", feature = "internals"))]
fn apply_override(
supported: &[Backend],
detected: Backend,
requested: Option<Backend>,
on_host: impl Fn(Backend) -> bool,
) -> Backend {
match requested {
Some(requested)
if supported.contains(&requested) && on_host(requested) && requested >= detected =>
{
requested
}
_ => detected,
}
}
#[cfg(feature = "internals")]
pub mod internals {
use crate::backend::Backend;
pub fn resolve_with(
supported: &[Backend],
on_host: impl Fn(Backend) -> bool,
requested: Option<Backend>,
) -> Backend {
apply_override(supported, detect(supported, &on_host), requested, &on_host)
}
pub fn apply_override(
supported: &[Backend],
detected: Backend,
requested: Option<Backend>,
on_host: impl Fn(Backend) -> bool,
) -> Backend {
super::apply_override(supported, detected, requested, on_host)
}
pub fn detect(supported: &[Backend], on_host: impl Fn(Backend) -> bool) -> Backend {
super::detect(supported, on_host)
}
}
#[cfg(test)]
#[cfg(any(feature = "std", feature = "internals"))]
mod tests {
use super::*;
use crate::backend::Backend;
fn x86_host() -> impl Fn(Backend) -> bool {
|b: Backend| {
matches!(
b,
Backend::V4x
| Backend::V4
| Backend::V3GfniCrypto
| Backend::V3
| Backend::V2
| Backend::V1
)
}
}
fn full_host() -> impl Fn(Backend) -> bool {
|_b: Backend| true
}
fn v1_only_host() -> impl Fn(Backend) -> bool {
|b: Backend| matches!(b, Backend::V1 | Backend::Scalar)
}
#[test]
fn detect_picks_strongest_supported_summoning() {
assert_eq!(detect(&[Backend::V2, Backend::V1], x86_host()), Backend::V2);
assert_eq!(
detect(&[Backend::V1, Backend::V2, Backend::V3], x86_host()),
Backend::V3
);
assert_eq!(detect(Backend::ALL, full_host()), Backend::V4x);
}
#[test]
fn detect_falls_back_to_scalar_when_nothing_supported_summons() {
assert_eq!(detect(&[], x86_host()), Backend::Scalar);
assert_eq!(
detect(&[Backend::NeonAes, Backend::Neon], x86_host()),
Backend::Scalar
);
assert_eq!(detect(&[Backend::Scalar], x86_host()), Backend::Scalar);
}
#[test]
fn narrowing_omits_host_best_resolves_to_strongest_supported() {
assert_eq!(
detect(&[Backend::V3, Backend::V2, Backend::V1], x86_host()),
Backend::V3
);
assert_eq!(detect(Backend::ALL, |b| b != Backend::V4x), Backend::V4);
assert_eq!(
detect(Backend::ALL, |b| b != Backend::V4x && b != Backend::V4),
Backend::V3GfniCrypto
);
assert_eq!(
detect(&[Backend::V3GfniCrypto, Backend::V3], full_host()),
Backend::V3GfniCrypto
);
assert_eq!(
detect(&[Backend::V1, Backend::Neon], x86_host()),
Backend::V1
);
let v3_host = |b: Backend| matches!(b, Backend::V3 | Backend::V2 | Backend::V1);
assert_eq!(detect(Backend::ALL, v3_host), Backend::V3);
}
#[test]
fn scalar_override_forces_scalar() {
let detected = detect(Backend::ALL, full_host());
assert_eq!(detected, Backend::V4x);
assert_eq!(
apply_override(Backend::ALL, detected, Some(Backend::Scalar), full_host()),
Backend::Scalar
);
}
#[test]
fn override_stronger_than_detected_is_ignored() {
const SET: &[Backend] = &[Backend::V3, Backend::V2, Backend::Scalar];
assert_eq!(
apply_override(SET, Backend::V2, Some(Backend::V3), |_| true),
Backend::V2
);
assert_eq!(
apply_override(SET, Backend::Scalar, Some(Backend::V3), |_| true),
Backend::Scalar
);
}
#[test]
fn override_within_family_downgrades() {
const SET: &[Backend] = &[
Backend::V4x,
Backend::V4,
Backend::V3GfniCrypto,
Backend::V3,
Backend::V2,
Backend::V1,
Backend::Scalar,
];
let detected = Backend::V4x;
assert_eq!(
apply_override(SET, detected, Some(Backend::V4), full_host()),
Backend::V4
);
assert_eq!(
apply_override(SET, detected, Some(Backend::V3GfniCrypto), full_host()),
Backend::V3GfniCrypto
);
assert_eq!(
apply_override(SET, detected, Some(Backend::V2), full_host()),
Backend::V2
);
assert_eq!(
apply_override(SET, detected, Some(Backend::Scalar), full_host()),
Backend::Scalar
);
assert_eq!(
apply_override(SET, detected, Some(Backend::V4x), full_host()),
Backend::V4x
);
}
#[test]
fn avx512_request_without_host_proof_is_ignored() {
const SET: &[Backend] = &[
Backend::V4x,
Backend::V4,
Backend::V3GfniCrypto,
Backend::Scalar,
];
let on_host = |b| b != Backend::V4x;
assert_eq!(detect(SET, on_host), Backend::V4);
assert_eq!(
apply_override(SET, Backend::V4, Some(Backend::V4x), on_host),
Backend::V4
);
let without_avx512 = |b| b != Backend::V4x && b != Backend::V4;
assert_eq!(detect(SET, without_avx512), Backend::V3GfniCrypto);
assert_eq!(
apply_override(
SET,
Backend::V3GfniCrypto,
Some(Backend::V4),
without_avx512
),
Backend::V3GfniCrypto
);
}
#[test]
fn cross_family_override_is_refused() {
const SET: &[Backend] = &[
Backend::V3,
Backend::V2,
Backend::V1,
Backend::NeonAes,
Backend::Neon,
Backend::Scalar,
];
let detected = detect(SET, x86_host());
assert_eq!(detected, Backend::V3);
assert_eq!(
apply_override(SET, detected, Some(Backend::Neon), x86_host()),
Backend::V3
);
assert_eq!(
apply_override(SET, detected, Some(Backend::NeonAes), x86_host()),
Backend::V3
);
}
#[test]
fn unavailable_within_family_request_is_refused() {
const SET: &[Backend] = &[Backend::V3, Backend::V2, Backend::V1, Backend::Scalar];
let detected = detect(SET, v1_only_host());
assert_eq!(detected, Backend::V1);
assert_eq!(
apply_override(SET, detected, Some(Backend::V2), v1_only_host()),
Backend::V1
);
assert_eq!(
apply_override(SET, detected, Some(Backend::Scalar), v1_only_host()),
Backend::Scalar
);
}
#[test]
fn override_not_in_supported_is_ignored() {
const SET: &[Backend] = &[Backend::V3, Backend::V1, Backend::Scalar];
assert_eq!(
apply_override(SET, Backend::V3, Some(Backend::V2), |_| true),
Backend::V3
);
}
#[test]
fn missing_or_unknown_override_leaves_detected() {
const SET: &[Backend] = &[Backend::V3, Backend::Scalar];
assert_eq!(
apply_override(SET, Backend::V3, None, |_| true),
Backend::V3
);
assert_eq!(Backend::from_name("turbo"), None);
}
#[test]
#[cfg(all(feature = "std", target_arch = "x86_64"))]
fn x86_detection_floor_is_v1() {
let detected = detect(Backend::ALL, Backend::probes_on_host);
assert!(
matches!(
detected,
Backend::V4x
| Backend::V4
| Backend::V3GfniCrypto
| Backend::V3
| Backend::V2
| Backend::V1
),
"detected {detected:?} on x86_64"
);
}
#[test]
#[cfg(all(feature = "std", target_arch = "aarch64"))]
fn aarch64_detection_floor_is_neon() {
let detected = detect(Backend::ALL, Backend::probes_on_host);
assert!(
matches!(detected, Backend::NeonAes | Backend::Neon),
"detected {detected:?} on aarch64"
);
}
#[test]
fn supported_membership_uses_equality_not_strength() {
const SET: &[Backend] = &[Backend::V3GfniCrypto, Backend::Scalar];
let detected = Backend::V3GfniCrypto;
assert_eq!(
apply_override(SET, detected, Some(Backend::V2), |b| b == Backend::V2),
Backend::V3GfniCrypto
);
}
}