1#[derive(Clone, Copy, Debug, Eq, PartialEq)]
4pub(super) struct BoolRegister(pub(super) u32);
5
6impl BoolRegister {
7 pub(super) fn next(count: &mut u32) -> Self {
8 let value = Self(*count);
9
10 *count = count
11 .checked_add(1)
12 .expect("rotation bool register count exceeds u32");
13
14 value
15 }
16
17 #[expect(
18 clippy::trivially_copy_pass_by_ref,
19 reason = "the stable boolean-register conversion API borrows its receiver"
20 )]
21 pub(super) const fn as_usize(&self) -> usize {
22 self.0 as usize
23 }
24}
25
26#[derive(Clone, Copy, Debug, Eq, PartialEq)]
27pub(super) struct IntRegister(pub(super) u32);
28
29impl IntRegister {
30 pub(super) fn next(count: &mut u32) -> Self {
31 let value = Self(*count);
32
33 *count = count
34 .checked_add(1)
35 .expect("rotation int register count exceeds u32");
36
37 value
38 }
39
40 #[expect(
41 clippy::trivially_copy_pass_by_ref,
42 reason = "the stable integer-register conversion API borrows its receiver"
43 )]
44 pub(super) const fn as_usize(&self) -> usize {
45 self.0 as usize
46 }
47}
48
49#[derive(Clone, Copy, Debug, Eq, PartialEq)]
50pub(super) struct FloatRegister(pub(super) u32);
51
52impl FloatRegister {
53 pub(super) fn next(count: &mut u32) -> Self {
54 let value = Self(*count);
55
56 *count = count
57 .checked_add(1)
58 .expect("rotation float register count exceeds u32");
59
60 value
61 }
62
63 #[expect(
64 clippy::trivially_copy_pass_by_ref,
65 reason = "the stable float-register conversion API borrows its receiver"
66 )]
67 pub(super) const fn as_usize(&self) -> usize {
68 self.0 as usize
69 }
70}
71
72#[derive(Clone, Copy, Debug, Eq, PartialEq)]
73pub(super) struct InstructionAddress(pub(super) u32);
74
75impl InstructionAddress {
76 pub(super) const fn placeholder() -> Self {
77 Self(u32::MAX)
78 }
79
80 pub(super) fn from_len(len: usize) -> Self {
81 Self(u32::try_from(len).expect("rotation instruction count exceeds u32"))
82 }
83
84 #[expect(
85 clippy::trivially_copy_pass_by_ref,
86 reason = "the stable instruction-address conversion API borrows its receiver"
87 )]
88 pub(super) const fn as_usize(&self) -> usize {
89 self.0 as usize
90 }
91}
92
93#[derive(Clone, Copy, Debug, PartialEq)]
94pub(super) enum BoolValue {
95 Constant(bool),
96 Register(BoolRegister),
97}
98
99#[derive(Clone, Copy, Debug, PartialEq)]
100pub(super) enum IntValue {
101 Constant(i64),
102 Register(IntRegister),
103}
104
105#[derive(Clone, Copy, Debug, PartialEq)]
106pub(super) enum FloatValue {
107 Constant(f64),
108 Register(FloatRegister),
109}
110
111#[derive(Clone, Copy, Debug, Eq, PartialEq)]
112#[cfg(feature = "rotation-optimizations")]
113pub(super) enum FloatComparison {
114 Gt,
115 Gte,
116 Lt,
117 Lte,
118 Eq,
119 Ne,
120}
121
122#[derive(Clone, Copy, Debug, PartialEq)]
123pub(super) enum Instruction {
124 LoadBool {
125 target: BoolRegister,
126 offset: usize,
127 },
128 LoadI32 {
129 target: IntRegister,
130 offset: usize,
131 },
132 LoadF64 {
133 target: FloatRegister,
134 offset: usize,
135 },
136 StoreBool {
137 offset: usize,
138 value: BoolValue,
139 },
140 StoreI32 {
141 offset: usize,
142 value: IntValue,
143 },
144 StoreF64 {
145 offset: usize,
146 value: FloatValue,
147 },
148 #[cfg(not(feature = "rotation-optimizations"))]
149 Now {
150 target: FloatRegister,
151 },
152 AddF {
153 target: FloatRegister,
154 lhs: FloatValue,
155 rhs: FloatValue,
156 },
157 SubF {
158 target: FloatRegister,
159 lhs: FloatValue,
160 rhs: FloatValue,
161 },
162 MulF {
163 target: FloatRegister,
164 lhs: FloatValue,
165 rhs: FloatValue,
166 },
167 SafeDivF {
168 target: FloatRegister,
169 lhs: FloatValue,
170 rhs: FloatValue,
171 },
172 TrueModF {
173 target: FloatRegister,
174 lhs: FloatValue,
175 rhs: FloatValue,
176 },
177 MinF {
178 target: FloatRegister,
179 lhs: FloatValue,
180 rhs: FloatValue,
181 },
182 MaxF {
183 target: FloatRegister,
184 lhs: FloatValue,
185 rhs: FloatValue,
186 },
187 FloorF {
188 target: FloatRegister,
189 value: FloatValue,
190 },
191 CeilF {
192 target: FloatRegister,
193 value: FloatValue,
194 },
195 AbsF {
196 target: FloatRegister,
197 value: FloatValue,
198 },
199 CmpGtF {
200 target: BoolRegister,
201 lhs: FloatValue,
202 rhs: FloatValue,
203 },
204 CmpGteF {
205 target: BoolRegister,
206 lhs: FloatValue,
207 rhs: FloatValue,
208 },
209 CmpLtF {
210 target: BoolRegister,
211 lhs: FloatValue,
212 rhs: FloatValue,
213 },
214 CmpLteF {
215 target: BoolRegister,
216 lhs: FloatValue,
217 rhs: FloatValue,
218 },
219 CmpEqF {
220 target: BoolRegister,
221 lhs: FloatValue,
222 rhs: FloatValue,
223 },
224 CmpNeF {
225 target: BoolRegister,
226 lhs: FloatValue,
227 rhs: FloatValue,
228 },
229 CmpEqI {
230 target: BoolRegister,
231 lhs: IntValue,
232 rhs: IntValue,
233 },
234 CmpNeI {
235 target: BoolRegister,
236 lhs: IntValue,
237 rhs: IntValue,
238 },
239 CmpGtI {
240 target: BoolRegister,
241 lhs: IntValue,
242 rhs: IntValue,
243 },
244 CmpGteI {
245 target: BoolRegister,
246 lhs: IntValue,
247 rhs: IntValue,
248 },
249 CmpLtI {
250 target: BoolRegister,
251 lhs: IntValue,
252 rhs: IntValue,
253 },
254 CmpLteI {
255 target: BoolRegister,
256 lhs: IntValue,
257 rhs: IntValue,
258 },
259 AndB {
260 target: BoolRegister,
261 lhs: BoolValue,
262 rhs: BoolValue,
263 },
264 OrB {
265 target: BoolRegister,
266 lhs: BoolValue,
267 rhs: BoolValue,
268 },
269 SetBool {
270 target: BoolRegister,
271 value: bool,
272 },
273 JumpIf {
274 condition: BoolValue,
275 target: InstructionAddress,
276 when_true: bool,
277 },
278 #[cfg(feature = "rotation-optimizations")]
279 JumpIfBufferBool {
280 offset: usize,
281 target: InstructionAddress,
282 when_true: bool,
283 },
284 #[cfg(feature = "rotation-optimizations")]
285 JumpIfCooldownNotReady {
286 cooldown_offset: usize,
287 bypass_aura_offset: Option<usize>,
288 target: InstructionAddress,
289 },
290 #[cfg(feature = "rotation-optimizations")]
291 JumpIfTimestampStateMismatch {
292 offset: usize,
293 expected_active: bool,
294 target: InstructionAddress,
295 },
296 #[cfg(feature = "rotation-optimizations")]
297 JumpIfBufferF64ComparisonFalse {
298 offset: usize,
299 rhs: f64,
300 comparison: FloatComparison,
301 target: InstructionAddress,
302 },
303 NotB {
304 target: BoolRegister,
305 value: BoolValue,
306 },
307 BoolToFloat {
308 target: FloatRegister,
309 value: BoolValue,
310 },
311 BoolToInt {
312 target: IntRegister,
313 value: BoolValue,
314 },
315 IntToFloat {
316 target: FloatRegister,
317 value: IntValue,
318 },
319 IntToBool {
320 target: BoolRegister,
321 value: IntValue,
322 },
323 FloatToBool {
324 target: BoolRegister,
325 value: FloatValue,
326 },
327 FloatToInt {
328 target: IntRegister,
329 value: FloatValue,
330 },
331 SelectF {
332 target: FloatRegister,
333 condition: BoolValue,
334 if_true: FloatValue,
335 if_false: FloatValue,
336 },
337 SelectI {
338 target: IntRegister,
339 condition: BoolValue,
340 if_true: IntValue,
341 if_false: IntValue,
342 },
343 SelectB {
344 target: BoolRegister,
345 condition: BoolValue,
346 if_true: BoolValue,
347 if_false: BoolValue,
348 },
349 #[cfg(feature = "rotation-optimizations")]
350 ReturnCast {
351 spell_id: u32,
352 empower_rank: u8,
353 },
354 ReturnCastIf {
355 condition: BoolValue,
356 spell_id: u32,
357 empower_rank: u8,
358 },
359 ReturnWaitIf {
360 condition: BoolValue,
361 seconds: f32,
362 },
363 ReturnPoolIf {
364 condition: BoolValue,
365 target: f32,
366 },
367 ReturnUseItemIf {
368 condition: BoolValue,
369 gear_slot: u8,
370 empower_rank: u8,
371 },
372 ReturnNone,
373}