helm_schema_core/
capability_liveness.rs1use crate::{ApiPresenceQuery, CapabilityGuard, HelperBranch, HelperBranchBody};
2
3pub trait CapabilityOracle: Send + Sync {
6 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#[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}