Skip to main content

wowlab_engine_domain/rotation/
decision_trace.rs

1use wowlab_types::sim::{Condition, RotationAction};
2
3#[rustfmt::skip]
4pub use wowlab_engine_ports::{ActionEvaluation, Decision, DecisionTrace, DecisionTraceSink, DecisionTraceTarget, EvaluationStatus, VecSink};
5
6/// One action's outcome, threaded into the backend's `record_action` hook.
7#[derive(Debug)]
8pub struct ActionRecord<'a> {
9    pub list_id: &'a str,
10    pub action_index: usize,
11    pub action: &'a RotationAction,
12    pub outcome: ActionOutcome<'a>,
13}
14
15/// Categorical outcome attached to one action by [`ActionRecord::outcome`].
16#[derive(Debug)]
17#[non_exhaustive]
18pub enum ActionOutcome<'a> {
19    Fired,
20    Executed,
21    Rejected { failing: &'a Condition },
22    NotReached,
23    Disabled,
24}
25
26impl ActionOutcome<'_> {
27    /// Corresponding wire-level status.
28    #[must_use]
29    pub fn status(&self) -> EvaluationStatus {
30        match self {
31            ActionOutcome::Fired => EvaluationStatus::Fired,
32            ActionOutcome::Executed => EvaluationStatus::Executed,
33            ActionOutcome::Rejected { .. } => EvaluationStatus::Rejected,
34            ActionOutcome::NotReached => EvaluationStatus::NotReached,
35            ActionOutcome::Disabled => EvaluationStatus::Disabled,
36        }
37    }
38}
39
40#[cfg(test)]
41mod tests {
42    use googletest::prelude::*;
43    use rstest::rstest;
44
45    use super::*;
46
47    #[gtest]
48    #[rstest]
49    #[case(ActionOutcome::Fired, EvaluationStatus::Fired)]
50    #[case(ActionOutcome::Executed, EvaluationStatus::Executed)]
51    #[case(ActionOutcome::NotReached, EvaluationStatus::NotReached)]
52    #[case(ActionOutcome::Disabled, EvaluationStatus::Disabled)]
53    fn action_outcome_status_maps_each_variant(
54        #[case] outcome: ActionOutcome<'_>,
55        #[case] expected: EvaluationStatus,
56    ) -> Result<()> {
57        verify_that!(outcome.status(), eq(expected))
58    }
59
60    #[gtest]
61    fn rejected_outcome_maps_to_rejected_status() -> Result<()> {
62        let cond = Condition::Bool { value: true };
63        let outcome = ActionOutcome::Rejected { failing: &cond };
64
65        verify_that!(outcome.status(), eq(EvaluationStatus::Rejected))
66    }
67}