use core::fmt;
use std::num::NonZeroUsize;
use crate::{CpuExecution, CpuFeatures, CpuInstructionSet};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InstructionPolicy {
Auto,
Portable,
Require(CpuInstructionSet),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CpuConfigError {
UnsupportedInstructionSet(CpuInstructionSet),
ParallelFeatureDisabled,
ThreadPool(String),
}
impl fmt::Display for CpuConfigError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::UnsupportedInstructionSet(value) => {
write!(f, "required CPU instruction set {value:?} is unavailable")
}
Self::ParallelFeatureDisabled => {
f.write_str("multiple workers require axiolid-backend-cpu's `parallel` feature")
}
Self::ThreadPool(reason) => {
write!(f, "failed to build local CPU thread pool: {reason}")
}
}
}
}
impl std::error::Error for CpuConfigError {}
#[derive(Debug, Clone, Copy)]
pub struct CpuExecutionBuilder {
instruction_policy: InstructionPolicy,
threads: NonZeroUsize,
}
impl Default for CpuExecutionBuilder {
fn default() -> Self {
Self {
instruction_policy: InstructionPolicy::Auto,
threads: NonZeroUsize::MIN,
}
}
}
impl CpuExecutionBuilder {
pub fn new() -> Self {
Self::default()
}
pub const fn instruction_policy(mut self, policy: InstructionPolicy) -> Self {
self.instruction_policy = policy;
self
}
pub const fn threads(mut self, threads: NonZeroUsize) -> Self {
self.threads = threads;
self
}
pub fn build(self) -> Result<CpuExecution, CpuConfigError> {
let features = CpuFeatures::detect();
let instruction_set = match self.instruction_policy {
InstructionPolicy::Portable => CpuInstructionSet::Portable,
InstructionPolicy::Auto => {
#[cfg(feature = "simd")]
{
features.best()
}
#[cfg(not(feature = "simd"))]
{
CpuInstructionSet::Portable
}
}
InstructionPolicy::Require(value) => {
if value != CpuInstructionSet::Portable && !cfg!(feature = "simd") {
return Err(CpuConfigError::UnsupportedInstructionSet(value));
}
if !features.supports(value) {
return Err(CpuConfigError::UnsupportedInstructionSet(value));
}
value
}
};
CpuExecution::from_configuration(instruction_set, features, self.threads)
}
}