Skip to main content

haz_domain/
scope.rs

1//! Task-set scope selection for `haz run` and `haz check`.
2//!
3//! The scope flags `--all` (`EXEC-024`) and `--workspace`
4//! (`EXEC-025`) are mutually exclusive; absent either, the selection
5//! defaults to the bearing project when one applies (`EXEC-022`),
6//! otherwise the whole workspace (`EXEC-023` default-target context,
7//! `AUX-009`). This module models that tri-state as a single value
8//! object so the mutually-exclusive pair of booleans cannot encode
9//! the rejected "both set" combination beyond the parser boundary.
10
11/// How broadly a task-set selection ranges over the workspace.
12///
13/// Produced from the `--all` / `--workspace` scope flags
14/// (`EXEC-024`, `EXEC-025`, `AUX-009`) and consumed by `haz run`
15/// target resolution and `haz check` validation counting. The two
16/// flags are mutually exclusive; representing the choice as one enum
17/// keeps the rejected "both flags set" combination unrepresentable
18/// in every downstream consumer.
19///
20/// # Examples
21///
22/// ```
23/// use haz_domain::scope::Scope;
24///
25/// assert_eq!(Scope::default(), Scope::Default);
26/// assert_eq!(Scope::from_flags(false, false), Some(Scope::Default));
27/// assert_eq!(Scope::from_flags(true, false), Some(Scope::All));
28/// assert_eq!(Scope::from_flags(false, true), Some(Scope::Workspace));
29/// assert_eq!(Scope::from_flags(true, true), None);
30/// ```
31#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
32pub enum Scope {
33    /// No scope flag: select the bearing project when one applies
34    /// (`EXEC-022`), otherwise the whole workspace (`EXEC-023`,
35    /// `AUX-009`).
36    #[default]
37    Default,
38    /// `--all`: every task in the current bearing scope (`EXEC-024`),
39    /// i.e. the bearing project when one applies, otherwise every
40    /// project in the workspace.
41    All,
42    /// `--workspace`: every task in every project, regardless of cwd
43    /// (`EXEC-025`).
44    Workspace,
45}
46
47impl Scope {
48    /// Reduce the mutually-exclusive `--all` / `--workspace` flag
49    /// pair to a single [`Scope`].
50    ///
51    /// Returns [`None`] for the rejected `(true, true)` combination
52    /// (the `EXEC-024` / `EXEC-025` / `AUX-009` scope mutex); the
53    /// caller maps that to its own diagnostic. The three accepted
54    /// combinations map to [`Scope::Default`], [`Scope::All`], and
55    /// [`Scope::Workspace`] respectively.
56    #[must_use]
57    pub fn from_flags(all: bool, workspace: bool) -> Option<Self> {
58        match (all, workspace) {
59            (false, false) => Some(Self::Default),
60            (true, false) => Some(Self::All),
61            (false, true) => Some(Self::Workspace),
62            (true, true) => None,
63        }
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use super::Scope;
70
71    #[test]
72    fn default_is_the_no_flag_variant() {
73        assert_eq!(Scope::default(), Scope::Default);
74    }
75
76    #[test]
77    fn from_flags_maps_neither_to_default() {
78        assert_eq!(Scope::from_flags(false, false), Some(Scope::Default));
79    }
80
81    #[test]
82    fn from_flags_maps_all_only_to_all() {
83        assert_eq!(Scope::from_flags(true, false), Some(Scope::All));
84    }
85
86    #[test]
87    fn from_flags_maps_workspace_only_to_workspace() {
88        assert_eq!(Scope::from_flags(false, true), Some(Scope::Workspace));
89    }
90
91    #[test]
92    fn from_flags_rejects_both_set() {
93        // The EXEC-024 / EXEC-025 / AUX-009 scope mutex: the parser
94        // never produces this pair, and the type cannot encode the
95        // result.
96        assert_eq!(Scope::from_flags(true, true), None);
97    }
98}