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
//! The `strict` policy: which runtime situations mmz errors on rather than
//! falling back to passthrough.
//!
//! Split out of `manifest.rs` once that file reached its own line cap. A
//! cohesive seam rather than a slice taken for size alone: `strict` is the one
//! manifest key that is a *policy about failure* rather than a declaration of
//! inputs, and both types here exist only to express it.
use std::collections::BTreeSet;
use serde::Deserialize;
/// A runtime situation mmz can either error on (strict) or fall back from.
///
/// Only the cases reachable once a manifest has loaded are configurable; a
/// missing or unparseable manifest always errors, since there is no `strict`
/// list to consult.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum StrictCase {
/// No rule's name is a token-prefix of the invoked command.
NoMatch,
/// A matched rule's scopes resolve to zero files on disk. A rule with a
/// `ttl` and no declared `inputs` never hits this: time is its input.
NoInputs,
}
/// The set of [`StrictCase`]s mmz errors on rather than passing through.
///
/// Absent from the manifest means every case (the safe default); an empty list
/// means none (full passthrough); a subset relaxes the rest.
#[derive(Debug, Clone, Deserialize)]
#[serde(transparent)]
pub struct StrictPolicy {
cases: BTreeSet<StrictCase>,
}
impl StrictPolicy {
/// Every case enforced — the default when `strict` is omitted.
#[must_use]
pub fn all() -> Self {
Self {
cases: [StrictCase::NoMatch, StrictCase::NoInputs]
.into_iter()
.collect(),
}
}
/// True when `case` should error instead of falling back.
#[must_use]
pub fn enforces(&self, case: StrictCase) -> bool {
self.cases.contains(&case)
}
}