use super::operations::OperationResult;
use crate::planning::semantics::ValueKind;
#[derive(Debug, Clone)]
pub(crate) enum BranchOutcome {
Taken,
NotTaken,
Propagate(OperationResult),
}
fn boolean_value(result: &OperationResult, context: &str) -> bool {
match result {
OperationResult::Value(literal) => match &literal.value {
ValueKind::Boolean(boolean) => *boolean,
other => panic!("BUG: {context} expected a boolean, got {other:?}"),
},
OperationResult::Veto(veto) => {
panic!("BUG: {context} inspected for a boolean while vetoed: {veto}")
}
}
}
pub(crate) fn condition_outcome(condition: &OperationResult) -> BranchOutcome {
if condition.vetoed() {
return BranchOutcome::Propagate(condition.clone());
}
if boolean_value(condition, "branch condition") {
BranchOutcome::Taken
} else {
BranchOutcome::NotTaken
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::evaluation::operations::VetoType;
use crate::planning::semantics::{DataPath, LiteralValue};
fn boolean(value: bool) -> OperationResult {
OperationResult::from_literal(LiteralValue::from_bool(value))
}
fn user_veto() -> OperationResult {
OperationResult::Veto(VetoType::UserDefined {
message: Some("blocked".to_string()),
})
}
fn missing_data_veto() -> OperationResult {
OperationResult::Veto(VetoType::missing_data(
DataPath::new(vec![], "x".to_string()),
None,
))
}
#[test]
fn propagates_any_veto() {
assert!(matches!(
condition_outcome(&user_veto()),
BranchOutcome::Propagate(_)
));
assert!(matches!(
condition_outcome(&missing_data_veto()),
BranchOutcome::Propagate(_)
));
}
#[test]
fn boolean_decides_when_not_vetoed() {
assert!(matches!(
condition_outcome(&boolean(true)),
BranchOutcome::Taken
));
assert!(matches!(
condition_outcome(&boolean(false)),
BranchOutcome::NotTaken
));
}
}