Skip to main content

weavatrix_worktree/
options.rs

1use crate::{
2    error::{TransactionPhase, WorktreeError, WorktreeErrorCode},
3    limits::WorktreeLimits,
4};
5
6/// Automatic preparation never starts more than this many workers by default.
7pub const DEFAULT_AUTO_WORKERS: usize = 4;
8
9/// Runtime policy for opening and preparing a worktree transaction.
10#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
11pub struct WorktreeOptions {
12    pub limits: WorktreeLimits,
13    /// Zero selects bounded automatic parallelism.
14    pub parallelism: usize,
15}
16
17impl WorktreeOptions {
18    #[must_use]
19    pub const fn with_limits(mut self, limits: WorktreeLimits) -> Self {
20        self.limits = limits;
21        self
22    }
23
24    /// Sets preparation workers. Zero restores bounded automatic selection.
25    #[must_use]
26    pub const fn with_parallelism(mut self, parallelism: usize) -> Self {
27        self.parallelism = parallelism;
28        self
29    }
30
31    pub fn validate(&self) -> Result<(), WorktreeError> {
32        self.limits.validate()?;
33        if self.parallelism > self.limits.max_workers {
34            return Err(WorktreeError::new(
35                WorktreeErrorCode::InvalidOptions,
36                TransactionPhase::Validate,
37                format!(
38                    "parallelism {} exceeds max_workers {}",
39                    self.parallelism, self.limits.max_workers
40                ),
41            ));
42        }
43        Ok(())
44    }
45
46    /// Resolves the bounded worker count for a known number of files.
47    #[must_use]
48    pub fn worker_count(&self, file_count: usize) -> usize {
49        if file_count == 0 {
50            return 0;
51        }
52        let requested = if self.parallelism == 0 {
53            std::thread::available_parallelism()
54                .map_or(1, core::num::NonZeroUsize::get)
55                .min(DEFAULT_AUTO_WORKERS)
56        } else {
57            self.parallelism
58        };
59        requested
60            .max(1)
61            .min(self.limits.max_workers)
62            .min(file_count)
63    }
64}
65
66#[cfg(test)]
67mod tests {
68    use crate::options::{DEFAULT_AUTO_WORKERS, WorktreeOptions};
69
70    #[test]
71    fn automatic_and_explicit_parallelism_are_bounded() {
72        let automatic = WorktreeOptions::default();
73        assert!((1..=DEFAULT_AUTO_WORKERS).contains(&automatic.worker_count(10)));
74        assert_eq!(automatic.worker_count(0), 0);
75
76        let explicit = automatic.with_parallelism(8);
77        assert_eq!(explicit.worker_count(5), 5);
78        assert!(explicit.validate().is_ok());
79    }
80}