axiolid_backend_cpu/
config.rs1use core::fmt;
4use std::num::NonZeroUsize;
5
6use crate::{CpuExecution, CpuFeatures, CpuInstructionSet};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum InstructionPolicy {
11 Auto,
13 Portable,
15 Require(CpuInstructionSet),
17}
18
19#[derive(Debug, Clone, PartialEq, Eq)]
21pub enum CpuConfigError {
22 UnsupportedInstructionSet(CpuInstructionSet),
24 ParallelFeatureDisabled,
26 ThreadPool(String),
28}
29
30impl fmt::Display for CpuConfigError {
31 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32 match self {
33 Self::UnsupportedInstructionSet(value) => {
34 write!(f, "required CPU instruction set {value:?} is unavailable")
35 }
36 Self::ParallelFeatureDisabled => {
37 f.write_str("multiple workers require axiolid-backend-cpu's `parallel` feature")
38 }
39 Self::ThreadPool(reason) => {
40 write!(f, "failed to build local CPU thread pool: {reason}")
41 }
42 }
43 }
44}
45
46impl std::error::Error for CpuConfigError {}
47
48#[derive(Debug, Clone, Copy)]
50pub struct CpuExecutionBuilder {
51 instruction_policy: InstructionPolicy,
52 threads: NonZeroUsize,
53}
54
55impl Default for CpuExecutionBuilder {
56 fn default() -> Self {
57 Self {
58 instruction_policy: InstructionPolicy::Auto,
59 threads: NonZeroUsize::MIN,
60 }
61 }
62}
63
64impl CpuExecutionBuilder {
65 pub fn new() -> Self {
67 Self::default()
68 }
69
70 pub const fn instruction_policy(mut self, policy: InstructionPolicy) -> Self {
72 self.instruction_policy = policy;
73 self
74 }
75
76 pub const fn threads(mut self, threads: NonZeroUsize) -> Self {
78 self.threads = threads;
79 self
80 }
81
82 pub fn build(self) -> Result<CpuExecution, CpuConfigError> {
84 let features = CpuFeatures::detect();
85 let instruction_set = match self.instruction_policy {
86 InstructionPolicy::Portable => CpuInstructionSet::Portable,
87 InstructionPolicy::Auto => {
88 #[cfg(feature = "simd")]
89 {
90 features.best()
91 }
92 #[cfg(not(feature = "simd"))]
93 {
94 CpuInstructionSet::Portable
95 }
96 }
97 InstructionPolicy::Require(value) => {
98 if value != CpuInstructionSet::Portable && !cfg!(feature = "simd") {
99 return Err(CpuConfigError::UnsupportedInstructionSet(value));
100 }
101 if !features.supports(value) {
102 return Err(CpuConfigError::UnsupportedInstructionSet(value));
103 }
104 value
105 }
106 };
107 CpuExecution::from_configuration(instruction_set, features, self.threads)
108 }
109}