use std::fmt;
pub const DEFAULT_WORKER_NUM: usize = 0;
pub const MIN_WORKER_NUM: usize = 1;
pub const MAX_WORKER_NUM: usize = 256;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct WorkerConfig {
worker_num: usize,
reactor_num: usize,
task_worker_num: usize,
}
impl WorkerConfig {
pub fn new() -> Self {
let cpu = num_cpus::get();
Self {
worker_num: cpu,
reactor_num: cpu,
task_worker_num: cpu,
}
}
pub fn with_worker_num(mut self, n: usize) -> Self {
self.worker_num = if n == 0 {
num_cpus::get()
} else {
n.clamp(MIN_WORKER_NUM, MAX_WORKER_NUM)
};
self
}
pub fn with_reactor_num(mut self, n: usize) -> Self {
self.reactor_num = if n == 0 {
num_cpus::get()
} else {
n.clamp(MIN_WORKER_NUM, MAX_WORKER_NUM)
};
self
}
pub fn with_task_worker_num(mut self, n: usize) -> Self {
self.task_worker_num = if n == 0 {
num_cpus::get()
} else {
n.clamp(MIN_WORKER_NUM, MAX_WORKER_NUM)
};
self
}
pub fn worker_num(&self) -> usize {
self.worker_num
}
pub fn reactor_num(&self) -> usize {
self.reactor_num
}
pub fn task_worker_num(&self) -> usize {
self.task_worker_num
}
pub fn cpu_num(&self) -> usize {
num_cpus::get()
}
pub fn validate(&self) -> bool {
self.worker_num >= MIN_WORKER_NUM
&& self.worker_num <= MAX_WORKER_NUM
&& self.reactor_num >= MIN_WORKER_NUM
&& self.reactor_num <= MAX_WORKER_NUM
&& self.task_worker_num >= MIN_WORKER_NUM
&& self.task_worker_num <= MAX_WORKER_NUM
}
pub fn from_env() -> Self {
let mut config = Self::new();
if let Ok(val) = std::env::var("SZ_RUST_WORKER_NUM") {
if let Ok(n) = val.parse::<usize>() {
config = config.with_worker_num(n);
}
}
config
}
}
impl Default for WorkerConfig {
fn default() -> Self {
Self::new()
}
}
impl fmt::Display for WorkerConfig {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"WorkerConfig{{worker_num={}, reactor_num={}, task_worker_num={}, cpu={}}}",
self.worker_num,
self.reactor_num,
self.task_worker_num,
self.cpu_num()
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_defaults_to_cpu_count() {
let config = WorkerConfig::new();
let cpu = num_cpus::get();
assert_eq!(config.worker_num(), cpu);
assert_eq!(config.reactor_num(), cpu);
assert_eq!(config.task_worker_num(), cpu);
}
#[test]
fn test_with_worker_num_custom() {
let config = WorkerConfig::new().with_worker_num(8);
assert_eq!(config.worker_num(), 8);
}
#[test]
fn test_with_worker_num_zero_falls_back_to_cpu() {
let config = WorkerConfig::new().with_worker_num(0);
assert_eq!(config.worker_num(), num_cpus::get());
}
#[test]
fn test_with_worker_num_exceeds_max_clamped() {
let config = WorkerConfig::new().with_worker_num(1024);
assert_eq!(config.worker_num(), MAX_WORKER_NUM);
}
#[test]
fn test_with_reactor_num_custom() {
let config = WorkerConfig::new().with_reactor_num(4);
assert_eq!(config.reactor_num(), 4);
}
#[test]
fn test_with_task_worker_num_custom() {
let config = WorkerConfig::new().with_task_worker_num(16);
assert_eq!(config.task_worker_num(), 16);
}
#[test]
fn test_cpu_num_matches_num_cpus() {
let config = WorkerConfig::new();
assert_eq!(config.cpu_num(), num_cpus::get());
}
#[test]
fn test_validate_valid_config() {
let config = WorkerConfig::new();
assert!(config.validate());
}
#[test]
fn test_validate_boundary_values() {
let config_min = WorkerConfig::new()
.with_worker_num(MIN_WORKER_NUM)
.with_reactor_num(MIN_WORKER_NUM)
.with_task_worker_num(MIN_WORKER_NUM);
assert!(config_min.validate());
let config_max = WorkerConfig::new()
.with_worker_num(MAX_WORKER_NUM)
.with_reactor_num(MAX_WORKER_NUM)
.with_task_worker_num(MAX_WORKER_NUM);
assert!(config_max.validate());
}
#[test]
fn test_from_env_default() {
std::env::remove_var("SZ_RUST_WORKER_NUM");
let config = WorkerConfig::from_env();
assert_eq!(config.worker_num(), num_cpus::get());
}
#[test]
fn test_from_env_custom() {
std::env::set_var("SZ_RUST_WORKER_NUM", "12");
let config = WorkerConfig::from_env();
assert_eq!(config.worker_num(), 12);
std::env::remove_var("SZ_RUST_WORKER_NUM");
}
#[test]
fn test_from_env_invalid_falls_back_to_default() {
std::env::set_var("SZ_RUST_WORKER_NUM", "not-a-number");
let config = WorkerConfig::from_env();
assert_eq!(config.worker_num(), num_cpus::get());
std::env::remove_var("SZ_RUST_WORKER_NUM");
}
#[test]
fn test_display_format() {
let config = WorkerConfig::new().with_worker_num(4);
let s = format!("{}", config);
assert!(s.contains("worker_num=4"));
assert!(s.contains("reactor_num="));
assert!(s.contains("task_worker_num="));
}
#[test]
fn test_default_equals_new() {
let config1 = WorkerConfig::default();
let config2 = WorkerConfig::new();
assert_eq!(config1, config2);
}
#[test]
fn test_clone_and_equality() {
let config1 = WorkerConfig::new().with_worker_num(4);
let config2 = config1.clone();
assert_eq!(config1, config2);
}
#[test]
fn test_builder_chaining() {
let config = WorkerConfig::new()
.with_worker_num(4)
.with_reactor_num(2)
.with_task_worker_num(8);
assert_eq!(config.worker_num(), 4);
assert_eq!(config.reactor_num(), 2);
assert_eq!(config.task_worker_num(), 8);
assert!(config.validate());
}
}