zero_pool/
pool.rs

1use crate::{TaskFnPointer, queue::Queue, task_future::TaskFuture, worker::spawn_worker};
2use std::{sync::Arc, thread::JoinHandle};
3
4pub struct ZeroPool {
5    queue: Arc<Queue>,
6    workers: Vec<JoinHandle<()>>,
7}
8
9impl ZeroPool {
10    /// Creates a new thread pool with worker count equal to available parallelism
11    ///
12    /// Worker count is determined by `std::thread::available_parallelism()`,
13    /// falling back to 1 if unavailable. This is usually the optimal choice
14    /// for CPU-bound workloads.
15    ///
16    /// # Examples
17    ///
18    /// ```rust
19    /// use zero_pool::ZeroPool;
20    /// let pool = ZeroPool::new();
21    /// ```
22    pub fn new() -> Self {
23        let worker_count = std::thread::available_parallelism()
24            .map(std::num::NonZeroUsize::get)
25            .unwrap_or(1);
26        Self::with_workers(worker_count)
27    }
28
29    /// Creates a new thread pool with the specified number of workers
30    ///
31    /// Use this when you need precise control over the worker count,
32    /// for example when coordinating with other thread pools or
33    /// when you know the optimal count for your specific workload.
34    ///
35    /// # Panics
36    ///
37    /// Panics if `worker_count` is 0.
38    ///
39    /// ```rust
40    /// use zero_pool::ZeroPool;
41    /// let pool = ZeroPool::with_workers(4);
42    /// ```
43    pub fn with_workers(worker_count: usize) -> Self {
44        assert!(worker_count > 0, "Must have at least one worker");
45
46        let queue = Arc::new(Queue::new());
47
48        let workers: Vec<JoinHandle<()>> = (0..worker_count)
49            .map(|id| spawn_worker(id, queue.clone()))
50            .collect();
51
52        ZeroPool { queue, workers }
53    }
54
55    /// Submit a single typed task with automatic pointer conversion
56    ///
57    /// This method provides type safety while maintaining performance.
58    /// The parameter struct must remain valid until the future completes.
59    /// This is the recommended method for submitting individual tasks.
60    ///
61    /// # Examples
62    ///
63    /// ```rust
64    /// use zero_pool::{ZeroPool, zp_define_task_fn, zp_write};
65    ///
66    /// struct MyTaskParams { value: u64, result: *mut u64 }
67    ///
68    /// zp_define_task_fn!(my_task_fn, MyTaskParams, |params| {
69    ///     zp_write!(params.result, params.value * 2);
70    /// });
71    ///
72    /// let pool = ZeroPool::new();
73    /// let mut result = 0u64;
74    /// let task_params = MyTaskParams { value: 42, result: &mut result };
75    /// let future = pool.submit_task(my_task_fn, &task_params);
76    /// future.wait();
77    /// assert_eq!(result, 84);
78    /// ```
79    pub fn submit_task<T>(&self, task_fn: TaskFnPointer, params: &T) -> TaskFuture {
80        let slice = std::slice::from_ref(params);
81        self.queue.push_task_batch(task_fn, slice)
82    }
83
84    /// Submit a batch of uniform tasks with automatic pointer conversion
85    ///
86    /// All tasks in the batch must be the same type and use the same task function.
87    /// This method handles the pointer conversion automatically and is the most
88    /// convenient way to submit large batches of similar work.
89    ///
90    /// # Examples
91    ///
92    /// ```rust
93    /// use zero_pool::{ZeroPool, zp_define_task_fn, zp_write};
94    ///
95    /// struct MyTaskParams { value: u64, result: *mut u64 }
96    ///
97    /// zp_define_task_fn!(my_task_fn, MyTaskParams, |params| {
98    ///     zp_write!(params.result, params.value * 2);
99    /// });
100    ///
101    /// let pool = ZeroPool::new();
102    /// let mut results = vec![0u64; 1000];
103    /// let task_params: Vec<_> = (0..1000)
104    ///     .map(|i| MyTaskParams { value: i as u64, result: &mut results[i] })
105    ///     .collect();
106    /// let future = pool.submit_batch_uniform(my_task_fn, &task_params);
107    /// future.wait();
108    /// assert_eq!(results[0], 0);
109    /// assert_eq!(results[1], 2);
110    /// assert_eq!(results[999], 1998);
111    /// ```
112    pub fn submit_batch_uniform<T>(&self, task_fn: TaskFnPointer, params_vec: &[T]) -> TaskFuture {
113        self.queue.push_task_batch(task_fn, params_vec)
114    }
115}
116
117impl Drop for ZeroPool {
118    fn drop(&mut self) {
119        self.queue.shutdown();
120
121        let workers = std::mem::take(&mut self.workers);
122        for handle in workers {
123            let _ = handle.join();
124        }
125    }
126}