Skip to main content

wowlab_engine_domain/rotation/lower/
eval_kind.rs

1use super::{
2    super::{
3        backend::RotationBackend, buffer::EvalKind, context::SpellUsableOffsets, expr::FieldType,
4    },
5    EvalValueAbstract,
6    ops::{
7        aura::aura_refreshable,
8        cooldown::{cooldown_full_recharge, cooldown_ready},
9        direct::positive_float,
10        resource::{resource_deficit, resource_deficit_pct, resource_pct, resource_time_to_max},
11        spell::{SpellUsableArgs, spell_usable},
12        timestamp,
13        unit::{unit_health_deficit, unit_health_pct},
14    },
15    typed_load,
16};
17
18// #t(fn: rust_cyclomatic_complexity) flat exhaustive match over the 16 EvalKind variants.
19pub(super) fn lower_eval_kind<B>(
20    b: &mut B,
21    kind: EvalKind,
22    offset: usize,
23    field_type: FieldType,
24    extras: Option<&SpellUsableOffsets>,
25    cooldown_bypass_aura_offset: Option<usize>,
26) -> EvalValueAbstract<B>
27where
28    B: RotationBackend,
29{
30    match kind {
31        EvalKind::Direct => typed_load(b, offset, field_type),
32        EvalKind::TimestampReady => EvalValueAbstract::Bool(timestamp::ready(b, offset)),
33        EvalKind::TimestampRemaining => EvalValueAbstract::Float(timestamp::remaining(b, offset)),
34        EvalKind::TimestampActive => EvalValueAbstract::Bool(timestamp::active(b, offset)),
35        EvalKind::TimestampElapsed => EvalValueAbstract::Float(timestamp::elapsed(b, offset)),
36        EvalKind::TimestampInactive => EvalValueAbstract::Bool(timestamp::inactive(b, offset)),
37        EvalKind::CooldownReady => {
38            EvalValueAbstract::Bool(cooldown_ready(b, offset, cooldown_bypass_aura_offset))
39        }
40        EvalKind::CooldownFullRecharge => {
41            EvalValueAbstract::Float(cooldown_full_recharge(b, offset))
42        }
43        EvalKind::AuraRefreshable => EvalValueAbstract::Bool(aura_refreshable(b, offset)),
44        EvalKind::PositiveFloat => EvalValueAbstract::Bool(positive_float(b, offset)),
45        EvalKind::ResourceDeficit => EvalValueAbstract::Float(resource_deficit(b, offset)),
46        EvalKind::ResourcePct => EvalValueAbstract::Float(resource_pct(b, offset)),
47        EvalKind::ResourceDeficitPct => EvalValueAbstract::Float(resource_deficit_pct(b, offset)),
48        EvalKind::ResourceTimeToMax => EvalValueAbstract::Float(resource_time_to_max(b, offset)),
49        EvalKind::UnitHealthPct => EvalValueAbstract::Float(unit_health_pct(b, offset)),
50        EvalKind::UnitHealthDeficit => EvalValueAbstract::Float(unit_health_deficit(b, offset)),
51        EvalKind::SpellUsable => {
52            // Missing extras (impossible for valid rotations) degrades to the bare is_enabled check.
53            let args = match extras {
54                Some(e) => SpellUsableArgs::from_offsets(offset, e),
55                None => SpellUsableArgs::bare(offset),
56            };
57
58            EvalValueAbstract::Bool(spell_usable(b, &args))
59        }
60        // `EvalKind` is `#[non_exhaustive]`, so this mandatory wildcard arm catches unhandled variants.
61        _ => {
62            debug_assert!(
63                false,
64                "lower_eval_kind: unhandled EvalKind variant {kind:?} (offset {offset}, {field_type:?})"
65            );
66            tracing::warn!(
67                ?kind,
68                offset,
69                ?field_type,
70                "lower_eval_kind: unhandled EvalKind variant, falling back to direct load"
71            );
72
73            typed_load(b, offset, field_type)
74        }
75    }
76}