Skip to main content

wowlab_engine_domain/rotation/
backend.rs

1//! Backend traits for rotation evaluation.
2
3use wowlab_types::sim::{Condition, RotationAction};
4
5use super::{
6    buffer::DenseBuffer, context::ContextSchema, decision_trace::ActionRecord, result::EvalResult,
7};
8
9/// Runtime dispatch trait for evaluating a compiled rotation.
10pub trait RuntimeBackend {
11    fn evaluate(&mut self, buffer: &mut DenseBuffer, now_secs: f64) -> EvalResult;
12
13    fn schema(&self) -> &ContextSchema;
14}
15
16/// Lowering trait of primitive ops both rotation backends must support, with bit-identical numeric semantics.
17// docref:start rotation-compiler-backend-trait
18pub trait RotationBackend {
19    type Bool: Copy;
20    type Int: Copy;
21    type Float: Copy;
22    // docref:end rotation-compiler-backend-trait
23
24    fn const_bool(&mut self, v: bool) -> Self::Bool;
25    fn const_i32(&mut self, v: i32) -> Self::Int;
26    fn const_i64(&mut self, v: i64) -> Self::Int;
27    fn const_f64(&mut self, v: f64) -> Self::Float;
28
29    fn load_bool(&mut self, offset: usize) -> Self::Bool;
30    fn load_i32(&mut self, offset: usize) -> Self::Int;
31    fn load_i64(&mut self, offset: usize) -> Self::Int;
32    fn load_f64(&mut self, offset: usize) -> Self::Float;
33
34    fn store_bool(&mut self, offset: usize, v: Self::Bool);
35    fn store_i32(&mut self, offset: usize, v: Self::Int);
36    fn store_f64(&mut self, offset: usize, v: Self::Float);
37
38    fn now(&mut self) -> Self::Float;
39
40    fn add_f(&mut self, a: Self::Float, b: Self::Float) -> Self::Float;
41    fn sub_f(&mut self, a: Self::Float, b: Self::Float) -> Self::Float;
42    fn mul_f(&mut self, a: Self::Float, b: Self::Float) -> Self::Float;
43    /// Returns 0.0 for any /0 (mirrors [`wowlab_types::numeric::safe_div`]).
44    fn safe_div_f(&mut self, a: Self::Float, b: Self::Float) -> Self::Float;
45    /// Mirrors [`wowlab_types::numeric::true_mod`].
46    fn true_mod_f(&mut self, a: Self::Float, b: Self::Float) -> Self::Float;
47    fn min_f(&mut self, a: Self::Float, b: Self::Float) -> Self::Float;
48    fn max_f(&mut self, a: Self::Float, b: Self::Float) -> Self::Float;
49    fn floor_f(&mut self, v: Self::Float) -> Self::Float;
50    fn ceil_f(&mut self, v: Self::Float) -> Self::Float;
51    fn abs_f(&mut self, v: Self::Float) -> Self::Float;
52
53    fn cmp_gt_f(&mut self, a: Self::Float, b: Self::Float) -> Self::Bool;
54    fn cmp_gte_f(&mut self, a: Self::Float, b: Self::Float) -> Self::Bool;
55    fn cmp_lt_f(&mut self, a: Self::Float, b: Self::Float) -> Self::Bool;
56    fn cmp_lte_f(&mut self, a: Self::Float, b: Self::Float) -> Self::Bool;
57    /// Epsilon-aware (mirrors [`wowlab_types::numeric::float_eq`]).
58    fn cmp_eq_f(&mut self, a: Self::Float, b: Self::Float) -> Self::Bool;
59    /// Epsilon-aware (mirrors [`wowlab_types::numeric::float_ne`]).
60    fn cmp_ne_f(&mut self, a: Self::Float, b: Self::Float) -> Self::Bool;
61    fn cmp_eq_i(&mut self, a: Self::Int, b: Self::Int) -> Self::Bool;
62    fn cmp_ne_i(&mut self, a: Self::Int, b: Self::Int) -> Self::Bool;
63    fn cmp_gt_i(&mut self, a: Self::Int, b: Self::Int) -> Self::Bool;
64    fn cmp_gte_i(&mut self, a: Self::Int, b: Self::Int) -> Self::Bool;
65    fn cmp_lt_i(&mut self, a: Self::Int, b: Self::Int) -> Self::Bool;
66    fn cmp_lte_i(&mut self, a: Self::Int, b: Self::Int) -> Self::Bool;
67
68    fn and_b(&mut self, a: Self::Bool, b: Self::Bool) -> Self::Bool;
69    fn or_b(&mut self, a: Self::Bool, b: Self::Bool) -> Self::Bool;
70    fn not_b(&mut self, a: Self::Bool) -> Self::Bool;
71
72    fn bool_to_float(&mut self, v: Self::Bool) -> Self::Float;
73    fn bool_to_int(&mut self, v: Self::Bool) -> Self::Int;
74    fn int_to_float(&mut self, v: Self::Int) -> Self::Float;
75    fn int_to_bool(&mut self, v: Self::Int) -> Self::Bool;
76    /// Exact `v != 0.0`.
77    fn float_to_bool(&mut self, v: Self::Float) -> Self::Bool;
78    /// `v as i64` (truncates).
79    fn float_to_int(&mut self, v: Self::Float) -> Self::Int;
80
81    // Select is eager: both branches evaluated; safe as branches are side-effect-free buffer reads.
82    fn select_f(&mut self, cond: Self::Bool, t: Self::Float, f: Self::Float) -> Self::Float;
83    fn select_i(&mut self, cond: Self::Bool, t: Self::Int, f: Self::Int) -> Self::Int;
84    fn select_b(&mut self, cond: Self::Bool, t: Self::Bool, f: Self::Bool) -> Self::Bool;
85
86    fn return_none_if(&mut self, cond: Self::Bool);
87    fn return_cast_if(&mut self, cond: Self::Bool, spell_id: u32, empower_rank: u8);
88    fn return_wait_if(&mut self, cond: Self::Bool, seconds: f32);
89    fn return_pool_if(&mut self, cond: Self::Bool, target: f32);
90    fn return_use_item_if(&mut self, cond: Self::Bool, gear_slot: u8, empower_rank: u8);
91
92    fn return_none(&mut self);
93
94    #[inline]
95    fn record_action(&mut self, _record: ActionRecord<'_>) {}
96
97    #[inline]
98    fn record_action_guarded(
99        &mut self,
100        _list_id: &str,
101        _action_index: usize,
102        _action: &RotationAction,
103        _is_terminator: bool,
104        _guard_held: Self::Bool,
105        _failing: &Condition,
106    ) {
107    }
108
109    #[inline]
110    fn begin_list_recording(&mut self, _list_id: &str) {}
111
112    #[inline]
113    fn end_list_recording(&mut self) {}
114}