Skip to main content

helm_schema_core/
capability_liveness.rs

1use crate::{ApiPresenceQuery, CapabilityGuard, HelperBranch, HelperBranchBody};
2
3/// Authoritative answer to a parsed `.Capabilities.APIVersions.Has` query for
4/// a specific Kubernetes version.
5pub trait CapabilityOracle: Send + Sync {
6    /// Returns an authoritative presence answer, or `None` when uncertain.
7    fn capability_has_query(&self, query: &ApiPresenceQuery) -> Option<bool>;
8}
9
10#[derive(Clone, Copy, Debug, Eq, PartialEq)]
11enum GuardLiveness {
12    Live,
13    Dead,
14    Unknown,
15}
16
17/// Resolve a typed-branch chain to the literal alternatives the chart would
18/// emit at runtime for the target K8s version. If a non-empty branch is not
19/// statically decidable, return no chosen branch so callers preserve all
20/// candidates instead of collapsing ambiguity to source order.
21#[must_use]
22pub fn live_literals<O: CapabilityOracle + ?Sized>(
23    branches: &[HelperBranch],
24    oracle: &O,
25) -> Vec<String> {
26    for branch in branches {
27        if branch.body.is_empty() {
28            continue;
29        }
30        match guard_liveness(branch.guard.as_ref(), oracle) {
31            GuardLiveness::Dead => continue,
32            GuardLiveness::Unknown => return Vec::new(),
33            GuardLiveness::Live => {}
34        }
35        match &branch.body {
36            HelperBranchBody::Literals { values } => return values.clone(),
37            HelperBranchBody::Nested { branches: nested } => {
38                let inner = live_literals(nested, oracle);
39                if !inner.is_empty() {
40                    return inner;
41                }
42            }
43        }
44    }
45    Vec::new()
46}
47
48fn guard_liveness<O: CapabilityOracle + ?Sized>(
49    guard: Option<&CapabilityGuard>,
50    oracle: &O,
51) -> GuardLiveness {
52    match guard {
53        None => GuardLiveness::Live,
54        Some(CapabilityGuard::Opaque { .. }) => GuardLiveness::Unknown,
55        Some(CapabilityGuard::Has { api }) => ApiPresenceQuery::parse_helm_literal(api)
56            .and_then(|query| oracle.capability_has_query(&query))
57            .map_or(GuardLiveness::Unknown, bool_liveness),
58        Some(CapabilityGuard::NotHas { api }) => ApiPresenceQuery::parse_helm_literal(api)
59            .and_then(|query| oracle.capability_has_query(&query))
60            .map_or(GuardLiveness::Unknown, |has| bool_liveness(!has)),
61    }
62}
63
64fn bool_liveness(live: bool) -> GuardLiveness {
65    if live {
66        GuardLiveness::Live
67    } else {
68        GuardLiveness::Dead
69    }
70}