1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
use crate::shutdown_mode::ShutdownMode;
use crate::thread_pool::ThreadPool;

/// Build a [ThreadPool]
///
/// Modify default thread pool parameters and build the thread pool
pub struct ThreadPoolBuilder {
    name: String,
    tasks: usize,
    queue_size: usize,
    join_error_handler: fn(String, String),
    shutdown_mode: ShutdownMode,
}

impl ThreadPoolBuilder {
    /// Create a new builder
    ///
    /// Default values:
    /// * `name` - "unnamed"
    /// * `tasks` - 1
    /// * `queue_size` - 16
    /// * `join_error_handler` - a simple panicking error handler
    /// * `shutdown_mode` - [ShutdownMode::Immediate]
    ///
    ///  # Example
    /// ```
    ///
    /// use command_executor::shutdown_mode::ShutdownMode;
    /// use command_executor::thread_pool::ThreadPool;
    /// use command_executor::thread_pool_builder::ThreadPoolBuilder;
    ///
    /// fn create_thread_pool() -> Result<ThreadPool, anyhow::Error> {
    ///     ThreadPoolBuilder::new()
    ///         .name_str("example")
    ///         .tasks(4)
    ///         .queue_size(16)
    ///         .shutdown_mode(ShutdownMode::CompletePending)
    ///         .build()
    /// }
    /// ```
    pub fn new() -> ThreadPoolBuilder {
        let join_error_handler = |name: String, message: String| {
            panic!("Thread {name} ended with and error {message}")
        };

        ThreadPoolBuilder {
            name: "unnamed".to_string(),
            tasks: 1,
            queue_size: 16,
            join_error_handler,
            shutdown_mode: ShutdownMode::Immediate,
        }
    }

    /// Set the base name for threads in the thread pool
    pub fn name(&mut self, name: String) -> &mut ThreadPoolBuilder {
        self.name = name.clone();
        self
    }

    /// Set the base name for threads in the thread pool. A convenience method that accepts &str
    pub fn name_str(&mut self, name: &str) -> &mut ThreadPoolBuilder {
        self.name = name.to_string();
        self
    }

    /// Set the number of threads in the thread pool
    pub fn tasks(&mut self, tasks: usize) -> &mut ThreadPoolBuilder {
        self.tasks = tasks;
        self
    }

    /// Specify the [ShutdownMode]
    pub fn shutdown_mode(&mut self, shutdown_mode: ShutdownMode) -> &mut ThreadPoolBuilder {
        self.shutdown_mode = shutdown_mode;
        self
    }

    /// Specify the queue size for the thread pool
    pub fn queue_size(&mut self, queue_size: usize) -> &mut ThreadPoolBuilder {
        self.queue_size = queue_size;
        self
    }

    /// Set the error handler that is called for each thread that exited with error during join
    pub fn join_error_handler(&mut self, join_error_handler: fn(String, String)) -> &mut ThreadPoolBuilder {
        self.join_error_handler = join_error_handler;
        self
    }

    /// Build the thread pool
    pub fn build(&self) -> Result<ThreadPool, anyhow::Error> {
        ThreadPool::new(
            self.name.clone(),
            self.tasks,
            self.queue_size,
            self.join_error_handler,
            self.shutdown_mode.clone(),
        )
    }
}