use std::{sync::Arc, thread, time::Duration};
use crate::{task::TaskListeners, RejectedTaskHandler, ThreadFactory, ThreadPool};
pub struct ThreadPoolBuilder {
pub(crate) channel_capacity: usize,
pub(crate) max_pool_size: usize,
pub(crate) core_pool_size: usize,
pub(crate) keep_alive_time: Duration,
pub(crate) rejected_task_handler: RejectedTaskHandler,
pub(crate) task_lisenters: TaskListeners,
pub(crate) thread_factory: Arc<ThreadFactory>,
}
impl Default for ThreadPoolBuilder {
fn default() -> Self {
Self {
channel_capacity: 1000,
max_pool_size: num_cpus::get_physical(),
core_pool_size: usize::max(1, num_cpus::get_physical() / 2),
keep_alive_time: Duration::from_secs(1),
rejected_task_handler: RejectedTaskHandler::Abort,
task_lisenters: TaskListeners {
before_execute: Box::new(|_| {}),
after_execute: Box::new(|_| {}),
},
thread_factory: Arc::new(thread::Builder::new),
}
}
}
impl ThreadPoolBuilder {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn channel_capacity(mut self, capacity: usize) -> Self {
self.channel_capacity = capacity;
self
}
#[must_use]
pub fn max_pool_size(mut self, size: usize) -> Self {
self.max_pool_size = size;
self
}
#[must_use]
pub fn core_pool_size(mut self, size: usize) -> Self {
self.core_pool_size = size;
self
}
#[must_use]
pub fn keep_alive_time(mut self, time: Duration) -> Self {
self.keep_alive_time = time;
self
}
#[must_use]
pub fn rejected_handler(mut self, handler: RejectedTaskHandler) -> Self {
self.rejected_task_handler = handler;
self
}
#[must_use]
pub fn lisenter_before_execute<F>(mut self, executor: F) -> Self
where
F: Fn(usize) + Send + Sync + 'static,
{
self.task_lisenters.before_execute = Box::new(executor);
self
}
#[must_use]
pub fn lisenter_after_execute<F>(mut self, executor: F) -> Self
where
F: Fn(usize) + Send + Sync + 'static,
{
self.task_lisenters.after_execute = Box::new(executor);
self
}
#[must_use]
pub fn thread_factory_fn<F>(mut self, f: F) -> Self
where
F: Fn() -> thread::Builder + Send + Sync + 'static,
{
self.thread_factory = Arc::new(f);
self
}
pub fn build(self) -> ThreadPool {
self.check_arguments();
ThreadPool::from_builder(self)
}
fn check_arguments(&self) {
if self.channel_capacity < self.max_pool_size {
panic!("max_tasks must < max_pool_size.",);
}
if self.max_pool_size < self.core_pool_size {
panic!("max_pool_size must < core_pool_size.",);
}
if self.core_pool_size == 0 {
panic!("core_pool_size can not be 0.");
}
}
}
#[cfg(test)]
mod tests {
use super::ThreadPoolBuilder;
#[test]
#[should_panic]
fn test_builder_args1() {
ThreadPoolBuilder::default()
.max_pool_size(7)
.channel_capacity(3)
.build();
}
#[test]
#[should_panic]
fn test_builder_args2() {
ThreadPoolBuilder::default()
.max_pool_size(6)
.core_pool_size(7)
.build();
}
#[test]
#[should_panic]
fn test_builder_args3() {
ThreadPoolBuilder::default().core_pool_size(0).build();
}
}