use crate::error::Error;
use core::fmt;
use core::num::NonZeroUsize;
const DEFAULT_STACK_BYTES: usize = 16 << 20;
pub struct Pool {
#[cfg(feature = "parallel")]
pub(crate) inner: rayon::ThreadPool,
pub(crate) width: NonZeroUsize,
}
impl Pool {
pub fn builder() -> PoolBuilder {
PoolBuilder::new()
}
pub fn width(&self) -> NonZeroUsize {
self.width
}
}
impl fmt::Debug for Pool {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Pool").field("width", &self.width).finish()
}
}
#[cfg_attr(not(feature = "parallel"), allow(dead_code))]
pub struct PoolBuilder {
threads: Option<usize>,
stack_size: usize,
thread_name: Option<Box<dyn Fn(usize) -> String>>,
on_start: Option<Box<dyn Fn(usize) + Send + Sync>>,
}
impl PoolBuilder {
fn new() -> Self {
PoolBuilder {
threads: None,
stack_size: DEFAULT_STACK_BYTES,
thread_name: None,
on_start: None,
}
}
#[must_use]
pub fn threads(mut self, n: usize) -> Self {
self.threads = Some(n);
self
}
#[must_use]
pub fn thread_name(mut self, f: impl Fn(usize) -> String + 'static) -> Self {
self.thread_name = Some(Box::new(f));
self
}
#[must_use]
pub fn stack_size(mut self, bytes: usize) -> Self {
self.stack_size = bytes;
self
}
#[must_use]
pub fn on_start(mut self, f: impl Fn(usize) + Send + Sync + 'static) -> Self {
self.on_start = Some(Box::new(f));
self
}
pub fn build(self) -> Result<Pool, Error> {
if self.threads == Some(0) {
return Err(Error::ZeroThreads);
}
self.build_checked()
}
#[cfg(feature = "parallel")]
fn build_checked(self) -> Result<Pool, Error> {
let n = self
.threads
.unwrap_or_else(|| std::thread::available_parallelism().map_or(1, NonZeroUsize::get));
let mut builder = rayon::ThreadPoolBuilder::new()
.num_threads(n)
.stack_size(self.stack_size);
if let Some(name) = self.thread_name {
builder = builder.thread_name(name);
}
if let Some(hook) = self.on_start {
builder = builder.start_handler(hook);
}
let inner = builder
.build()
.map_err(|e| Error::PoolBuild(e.to_string()))?;
let width = NonZeroUsize::new(inner.current_num_threads()).unwrap_or(NonZeroUsize::MIN);
Ok(Pool { inner, width })
}
#[cfg(not(feature = "parallel"))]
fn build_checked(self) -> Result<Pool, Error> {
Ok(Pool {
width: NonZeroUsize::MIN,
})
}
}
impl fmt::Debug for PoolBuilder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PoolBuilder")
.field("threads", &self.threads)
.field("stack_size", &self.stack_size)
.finish_non_exhaustive()
}
}