use std::num::NonZeroUsize;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Jobs {
Global,
Threads(NonZeroUsize),
}
impl Jobs {
pub const SERIAL: Self = Self::Threads(NonZeroUsize::MIN);
#[must_use]
#[inline]
pub const fn from_count(count: usize) -> Self {
match NonZeroUsize::new(count) {
Some(threads) => Self::Threads(threads),
None => Self::Global,
}
}
#[must_use]
#[inline]
pub const fn is_serial(self) -> bool {
matches!(self, Self::Threads(threads) if threads.get() == 1)
}
}
impl Default for Jobs {
#[inline]
fn default() -> Self {
Self::SERIAL
}
}
#[must_use]
#[inline]
pub fn default_workers() -> usize {
let physical = num_cpus::get_physical();
let logical = std::thread::available_parallelism().map_or(1, NonZeroUsize::get);
if physical == 0 {
logical.max(1)
} else {
physical.min(logical).max(1)
}
}
#[cfg(test)]
mod tests {
use super::Jobs;
use super::default_workers;
#[test]
fn zero_selects_global_pool() {
assert_eq!(Jobs::from_count(0), Jobs::Global);
}
#[test]
fn one_is_serial() {
assert_eq!(Jobs::from_count(1), Jobs::SERIAL);
assert!(Jobs::SERIAL.is_serial());
assert!(!Jobs::Global.is_serial());
assert!(!Jobs::from_count(2).is_serial());
}
#[test]
fn default_is_serial() {
assert_eq!(Jobs::default(), Jobs::SERIAL);
}
#[test]
fn default_workers_use_physical_limit() {
let logical = std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get);
let physical = num_cpus::get_physical();
let workers = default_workers();
assert!(workers >= 1);
assert!(workers <= logical);
if physical > 0 {
assert!(workers <= physical);
assert_eq!(workers, physical.min(logical));
}
}
#[test]
fn default_workers_never_falls_below_one() {
for _ in 0..8 {
assert!(default_workers() >= 1);
}
let logical = std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get);
assert!(default_workers() <= logical.max(1));
}
#[test]
fn from_count_covers_edges() {
assert_eq!(Jobs::from_count(0), Jobs::Global);
assert_eq!(Jobs::from_count(1), Jobs::SERIAL);
assert!(!Jobs::from_count(2).is_serial());
assert!(!Jobs::from_count(usize::MAX).is_serial());
assert_ne!(Jobs::from_count(usize::MAX), Jobs::Global);
assert_ne!(Jobs::from_count(usize::MAX), Jobs::SERIAL);
assert!(!Jobs::from_count(64).is_serial());
}
}