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}