1use luau_common::ByteSlice;
2
3use crate::call::ThreadStack;
4use crate::gc::{GcBarrier, GcRuntime};
5use crate::metamethod::MetamethodRuntime;
6use crate::number::{
7 LUAI_MAXINT2STR, LUAI_MAXNUM2STR, clamp_f, int_to_str, lerp_f, num_to_str, sign_f,
8};
9use crate::state::ThreadState;
10use crate::string::StringRuntime;
11use crate::table::TableRuntime;
12use crate::thread::Thread;
13use crate::value::{TValue, TValueCursor};
14
15use core::mem::MaybeUninit;
16use core::ptr;
17
18use crate::Table;
19use crate::buffer::Buffer;
20use crate::gc::GcObject;
21use crate::handle::RawHandle;
22use crate::metamethod::TmEvent;
23use crate::number::str_to_num;
24use crate::types::{LUA_TNIL, LUA_TTABLE, LUA_TUSERDATA};
25
26pub type LuauFastFunction = unsafe fn(&Thread, TValueCursor, TValue, i32, TValueCursor, i32) -> i32;
27unsafe fn missing(
31 _thread: &Thread,
32 _result: TValueCursor,
33 _arg0: TValue,
34 _nresults: i32,
35 _args: TValueCursor,
36 _nparams: i32,
37) -> i32 {
38 -1
39}
40
41unsafe fn assert(
43 _thread: &Thread,
44 _result: TValueCursor,
45 arg0: TValue,
46 nresults: i32,
47 _args: TValueCursor,
48 nparams: i32,
49) -> i32 {
50 if nparams >= 1 && nresults == 0 && !arg0.is_false() {
51 0
52 } else {
53 -1
54 }
55}
56
57unsafe fn type_(
59 thread: &Thread,
60 result: TValueCursor,
61 arg0: TValue,
62 nresults: i32,
63 _args: TValueCursor,
64 nparams: i32,
65) -> i32 {
66 if nparams >= 1 && nresults <= 1 {
67 unsafe {
68 result
69 .value_unchecked()
70 .set_string_value(thread.global().type_name(arg0.tt() as usize))
71 };
72 1
73 } else {
74 -1
75 }
76}
77
78unsafe fn len(
80 _thread: &Thread,
81 result: TValueCursor,
82 arg0: TValue,
83 nresults: i32,
84 _args: TValueCursor,
85 nparams: i32,
86) -> i32 {
87 if nparams >= 1 && nresults <= 1 && arg0.is_string() {
88 unsafe { result.value_unchecked() }.set_number(unsafe {
89 arg0.string_value().as_ptr().as_ref().unwrap_unchecked().len as f64
90 });
91 return 1;
92 }
93 -1
94}
95
96unsafe fn type_of(
98 thread: &Thread,
99 result: TValueCursor,
100 arg0: TValue,
101 nresults: i32,
102 _args: TValueCursor,
103 nparams: i32,
104) -> i32 {
105 if nparams >= 1 && nresults <= 1 {
106 unsafe { result.value_unchecked() }
107 .set_string_value(unsafe { thread.obj_type_name_str(arg0) });
108 1
109 } else {
110 -1
111 }
112}
113
114unsafe fn select(
116 thread: &Thread,
117 result: TValueCursor,
118 arg0: TValue,
119 nresults: i32,
120 _args: TValueCursor,
121 nparams: i32,
122) -> i32 {
123 if nparams == 1 && nresults == 1 {
124 let (base, n, hash_selector) = unsafe {
125 let ci = thread.current_call_info();
126 let func = ci.function();
127 let proto = ci.proto().unwrap_unchecked();
128 let base = thread.stack_base();
129 let n = base.offset_from(func) as i32
130 - proto.as_ptr().as_ref().unwrap_unchecked().num_params as i32
131 - 1;
132 let hash_selector =
133 arg0.is_string() && arg0.string_value().as_bytes().first() == Some(&b'#');
134 (base, n, hash_selector)
135 };
136
137 if arg0.is_number() {
138 let i = arg0.number_value() as i32;
139 if ((i - 1) as u32) < (n as u32) {
140 unsafe { result.value_unchecked() }.set_obj(unsafe {
141 base.sub(n as usize).add((i - 1) as usize).value_unchecked()
142 });
143 return 1;
144 }
145 } else if hash_selector {
146 unsafe { result.value_unchecked() }.set_number(n as f64);
147 return 1;
148 }
149 }
150 -1
151}
152
153unsafe fn to_number(
155 _thread: &Thread,
156 result: TValueCursor,
157 arg0: TValue,
158 nresults: i32,
159 _args: TValueCursor,
160 nparams: i32,
161) -> i32 {
162 if nparams == 1 && nresults <= 1 {
163 if arg0.is_number() {
164 unsafe { result.value_unchecked() }.set_number(arg0.number_value());
165 } else if arg0.is_string() {
166 let string = arg0.string_value();
167 if let Some(value) = str_to_num(unsafe { string.as_bytes() }) {
168 unsafe { result.value_unchecked() }.set_number(value);
169 } else {
170 unsafe { result.value_unchecked() }.set_nil();
171 }
172 } else {
173 unsafe { result.value_unchecked() }.set_nil();
174 }
175 1
176 } else {
177 -1
178 }
179}
180
181unsafe fn to_string(
183 thread: &Thread,
184 result: TValueCursor,
185 arg0: TValue,
186 nresults: i32,
187 _args: TValueCursor,
188 nparams: i32,
189) -> i32 {
190 if nparams < 1 || nresults > 1 {
191 return -1;
192 }
193
194 unsafe {
195 if arg0.is_nil() {
196 result
197 .value_unchecked()
198 .set_string_value(thread.global().type_name(LUA_TNIL as usize));
199 } else if arg0.is_boolean() {
200 let bytes: &[u8] = if arg0.boolean_value() != 0 {
201 b"true"
202 } else {
203 b"false"
204 };
205 let Ok(s) = thread.intern_string(bytes.as_bstr()) else {
206 return -1;
207 };
208 result.value_unchecked().set_string_value(s);
209 } else if arg0.is_number() {
210 if thread.needs_gc() {
211 return -1;
212 }
213 let mut buffer = [0u8; LUAI_MAXNUM2STR];
214 let len = num_to_str(&mut buffer, arg0.number_value());
215 let Ok(s) = thread.intern_string(buffer[..len].as_bstr()) else {
216 return -1;
217 };
218 result.value_unchecked().set_string_value(s);
219 } else if arg0.is_string() {
220 result
221 .value_unchecked()
222 .set_string_value(arg0.string_value());
223 } else if arg0.is_integer() {
224 if thread.needs_gc() {
225 return -1;
226 }
227 let mut buffer = [0u8; LUAI_MAXINT2STR];
228 let len = int_to_str(&mut buffer, arg0.integer_value());
229 let Ok(s) = thread.intern_string(buffer[..len].as_bstr()) else {
230 return -1;
231 };
232 result.value_unchecked().set_string_value(s);
233 } else {
234 return -1;
235 }
236
237 1
238 }
239}
240
241macro_rules! unary_num {
244 ($doc:literal, $name:ident, $op:expr) => {
245 #[doc = $doc]
246 unsafe fn $name(
247 _thread: &Thread,
248 result: TValueCursor,
249 arg0: TValue,
250 nresults: i32,
251 _args: TValueCursor,
252 nparams: i32,
253 ) -> i32 {
254 if nparams >= 1 && nresults <= 1 && arg0.is_number() {
255 unsafe { result.value_unchecked() }.set_number(($op)(arg0.number_value()));
256 1
257 } else {
258 -1
259 }
260 }
261 };
262}
263
264macro_rules! binary_num {
265 ($doc:literal, $name:ident, $op:expr) => {
266 #[doc = $doc]
267 unsafe fn $name(
268 _thread: &Thread,
269 result: TValueCursor,
270 arg0: TValue,
271 nresults: i32,
272 args: TValueCursor,
273 nparams: i32,
274 ) -> i32 {
275 if nparams >= 2
276 && nresults <= 1
277 && arg0.is_number()
278 && unsafe { args.value_unchecked() }.is_number()
279 {
280 unsafe { result.value_unchecked() }.set_number(($op)(
281 arg0.number_value(),
282 unsafe { args.value_unchecked() }.number_value(),
283 ));
284 1
285 } else {
286 -1
287 }
288 }
289 };
290}
291
292unary_num!("`luauF_abs`", abs, f64::abs);
293unary_num!("`luauF_acos`", acos, f64::acos);
294unary_num!("`luauF_asin`", asin, f64::asin);
295binary_num!("`luauF_atan2`", atan2, f64::atan2);
296unary_num!("`luauF_atan`", atan, f64::atan);
297unary_num!("`luauF_ceil`", ceil, f64::ceil);
298unary_num!("`luauF_cosh`", cosh, f64::cosh);
299unary_num!("`luauF_cos`", cos, f64::cos);
300unary_num!("`luauF_exp`", exp, f64::exp);
301unary_num!("`luauF_floor`", floor, f64::floor);
302binary_num!("`luauF_fmod`", fmod, |a: f64, b: f64| a % b);
303binary_num!("`luauF_pow`", pow, f64::powf);
304unary_num!("`luauF_sinh`", sinh, f64::sinh);
305unary_num!("`luauF_sin`", sin, f64::sin);
306unary_num!("`luauF_sqrt`", sqrt, f64::sqrt);
307unary_num!("`luauF_tanh`", tanh, f64::tanh);
308unary_num!("`luauF_tan`", tan, f64::tan);
309
310unsafe fn deg(
312 _thread: &Thread,
313 result: TValueCursor,
314 arg0: TValue,
315 nresults: i32,
316 _args: TValueCursor,
317 nparams: i32,
318) -> i32 {
319 if nparams >= 1 && nresults <= 1 && arg0.is_number() {
320 let radians_per_degree = std::f64::consts::PI / 180.0;
321 unsafe { result.value_unchecked() }.set_number(arg0.number_value() / radians_per_degree);
322 1
323 } else {
324 -1
325 }
326}
327
328unsafe fn frexp(
330 _thread: &Thread,
331 result: TValueCursor,
332 arg0: TValue,
333 nresults: i32,
334 _args: TValueCursor,
335 nparams: i32,
336) -> i32 {
337 if nparams >= 1 && nresults <= 2 && arg0.is_number() {
338 let value = arg0.number_value();
339 if value == 0.0 {
340 unsafe { result.value_unchecked() }.set_number(0.0);
341 unsafe { result.add(1).value_unchecked() }.set_number(0.0);
342 return 2;
343 }
344
345 let abs = value.abs();
346 let exponent = abs.log2().floor() as i32 + 1;
347 let fraction = value / 2.0f64.powi(exponent);
348 unsafe { result.value_unchecked() }.set_number(fraction);
349 unsafe { result.add(1).value_unchecked() }.set_number(exponent as f64);
350 2
351 } else {
352 -1
353 }
354}
355
356unsafe fn ldexp(
358 _thread: &Thread,
359 result: TValueCursor,
360 arg0: TValue,
361 nresults: i32,
362 args: TValueCursor,
363 nparams: i32,
364) -> i32 {
365 if nparams >= 2
366 && nresults <= 1
367 && arg0.is_number()
368 && unsafe { args.value_unchecked() }.is_number()
369 {
370 unsafe { result.value_unchecked() }.set_number(
371 arg0.number_value()
372 * 2.0f64.powi(unsafe { args.value_unchecked() }.number_value() as i32),
373 );
374 1
375 } else {
376 -1
377 }
378}
379
380unsafe fn log10(
382 _thread: &Thread,
383 result: TValueCursor,
384 arg0: TValue,
385 nresults: i32,
386 _args: TValueCursor,
387 nparams: i32,
388) -> i32 {
389 if nparams >= 1 && nresults <= 1 && arg0.is_number() {
390 unsafe { result.value_unchecked() }.set_number(arg0.number_value().log10());
391 1
392 } else {
393 -1
394 }
395}
396
397unsafe fn log(
399 _thread: &Thread,
400 result: TValueCursor,
401 arg0: TValue,
402 nresults: i32,
403 args: TValueCursor,
404 nparams: i32,
405) -> i32 {
406 if nparams >= 1 && nresults <= 1 && arg0.is_number() {
407 let a1 = arg0.number_value();
408 if nparams == 1 {
409 unsafe { result.value_unchecked() }.set_number(a1.ln());
410 return 1;
411 } else if unsafe { args.value_unchecked() }.is_number() {
412 let base = unsafe { args.value_unchecked() }.number_value();
413 let value = if base == 2.0 {
414 a1.log2()
415 } else if base == 10.0 {
416 a1.log10()
417 } else {
418 a1.ln() / base.ln()
419 };
420 unsafe { result.value_unchecked() }.set_number(value);
421 return 1;
422 }
423 }
424 -1
425}
426
427unsafe fn max(
429 _thread: &Thread,
430 result: TValueCursor,
431 arg0: TValue,
432 nresults: i32,
433 args: TValueCursor,
434 nparams: i32,
435) -> i32 {
436 if nparams >= 2
437 && nresults <= 1
438 && arg0.is_number()
439 && unsafe { args.value_unchecked() }.is_number()
440 {
441 let a1 = arg0.number_value();
442 let a2 = unsafe { args.value_unchecked() }.number_value();
443 let mut r = if a2 > a1 { a2 } else { a1 };
444 for index in 3..=nparams {
445 let arg = unsafe { args.add((index - 2) as usize).value_unchecked() };
446 if !arg.is_number() {
447 return -1;
448 }
449 let a = arg.number_value();
450 r = if a > r { a } else { r };
451 }
452 unsafe { result.value_unchecked() }.set_number(r);
453 1
454 } else {
455 -1
456 }
457}
458
459unsafe fn min(
461 _thread: &Thread,
462 result: TValueCursor,
463 arg0: TValue,
464 nresults: i32,
465 args: TValueCursor,
466 nparams: i32,
467) -> i32 {
468 if nparams >= 2
469 && nresults <= 1
470 && arg0.is_number()
471 && unsafe { args.value_unchecked() }.is_number()
472 {
473 let a1 = arg0.number_value();
474 let a2 = unsafe { args.value_unchecked() }.number_value();
475 let mut r = if a2 < a1 { a2 } else { a1 };
476 for index in 3..=nparams {
477 let arg = unsafe { args.add((index - 2) as usize).value_unchecked() };
478 if !arg.is_number() {
479 return -1;
480 }
481 let a = arg.number_value();
482 r = if a < r { a } else { r };
483 }
484 unsafe { result.value_unchecked() }.set_number(r);
485 1
486 } else {
487 -1
488 }
489}
490
491unsafe fn modf(
493 _thread: &Thread,
494 result: TValueCursor,
495 arg0: TValue,
496 nresults: i32,
497 _args: TValueCursor,
498 nparams: i32,
499) -> i32 {
500 if nparams >= 1 && nresults <= 2 && arg0.is_number() {
501 let a1 = arg0.number_value();
502 let ip = a1.trunc();
503 let fp = a1 - ip;
504 unsafe { result.value_unchecked() }.set_number(ip);
505 unsafe { result.add(1).value_unchecked() }.set_number(fp);
506 2
507 } else {
508 -1
509 }
510}
511
512unsafe fn rad(
514 _thread: &Thread,
515 result: TValueCursor,
516 arg0: TValue,
517 nresults: i32,
518 _args: TValueCursor,
519 nparams: i32,
520) -> i32 {
521 if nparams >= 1 && nresults <= 1 && arg0.is_number() {
522 let radians_per_degree = std::f64::consts::PI / 180.0;
523 unsafe { result.value_unchecked() }.set_number(arg0.number_value() * radians_per_degree);
524 1
525 } else {
526 -1
527 }
528}
529
530unsafe fn clamp(
532 _thread: &Thread,
533 result: TValueCursor,
534 arg0: TValue,
535 nresults: i32,
536 args: TValueCursor,
537 nparams: i32,
538) -> i32 {
539 if nparams >= 3
540 && nresults <= 1
541 && arg0.is_number()
542 && unsafe { args.value_unchecked() }.is_number()
543 && unsafe { args.add(1).value_unchecked().is_number() }
544 {
545 let value = arg0.number_value();
546 let min = unsafe { args.value_unchecked() }.number_value();
547 let max = unsafe { args.add(1).value_unchecked().number_value() };
548 if min <= max {
549 let value = if value < min { min } else { value };
550 unsafe { result.value_unchecked() }.set_number(if value > max { max } else { value });
551 return 1;
552 }
553 }
554
555 -1
556}
557
558unsafe fn sign(
560 _thread: &Thread,
561 result: TValueCursor,
562 arg0: TValue,
563 nresults: i32,
564 _args: TValueCursor,
565 nparams: i32,
566) -> i32 {
567 if nparams >= 1 && nresults <= 1 && arg0.is_number() {
568 let value = arg0.number_value();
569 unsafe { result.value_unchecked() }.set_number(if value > 0.0 {
570 1.0
571 } else if value < 0.0 {
572 -1.0
573 } else {
574 0.0
575 });
576 return 1;
577 }
578
579 -1
580}
581
582unsafe fn round(
584 _thread: &Thread,
585 result: TValueCursor,
586 arg0: TValue,
587 nresults: i32,
588 _args: TValueCursor,
589 nparams: i32,
590) -> i32 {
591 if nparams >= 1 && nresults <= 1 && arg0.is_number() {
592 unsafe { result.value_unchecked() }.set_number(arg0.number_value().round());
593 return 1;
594 }
595
596 -1
597}
598
599unsafe fn is_nan(
601 _thread: &Thread,
602 result: TValueCursor,
603 arg0: TValue,
604 nresults: i32,
605 _args: TValueCursor,
606 nparams: i32,
607) -> i32 {
608 if nparams >= 1 && nresults <= 1 && arg0.is_number() {
609 unsafe { result.value_unchecked() }.set_boolean(i32::from(arg0.number_value().is_nan()));
610 return 1;
611 }
612 -1
613}
614
615unsafe fn is_inf(
617 _thread: &Thread,
618 result: TValueCursor,
619 arg0: TValue,
620 nresults: i32,
621 _args: TValueCursor,
622 nparams: i32,
623) -> i32 {
624 if nparams >= 1 && nresults <= 1 && arg0.is_number() {
625 unsafe { result.value_unchecked() }
626 .set_boolean(i32::from(arg0.number_value().is_infinite()));
627 return 1;
628 }
629 -1
630}
631
632unsafe fn is_finite(
634 _thread: &Thread,
635 result: TValueCursor,
636 arg0: TValue,
637 nresults: i32,
638 _args: TValueCursor,
639 nparams: i32,
640) -> i32 {
641 if nparams >= 1 && nresults <= 1 && arg0.is_number() {
642 unsafe { result.value_unchecked() }.set_boolean(i32::from(arg0.number_value().is_finite()));
643 return 1;
644 }
645 -1
646}
647
648unsafe fn ar_shift(
652 _thread: &Thread,
653 result: TValueCursor,
654 arg0: TValue,
655 nresults: i32,
656 args: TValueCursor,
657 nparams: i32,
658) -> i32 {
659 if nparams >= 2
660 && nresults <= 1
661 && arg0.is_number()
662 && unsafe { args.value_unchecked() }.is_number()
663 {
664 let u = (arg0.number_value() as i64) as u32;
665 let s = unsafe { args.value_unchecked() }.number_value() as i32;
666 if (s as u32) < 32 {
667 unsafe { result.value_unchecked() }.set_number(((u as i32) >> s) as u32 as f64);
668 return 1;
669 }
670 }
671 -1
672}
673
674unsafe fn band(
676 _thread: &Thread,
677 result: TValueCursor,
678 arg0: TValue,
679 nresults: i32,
680 args: TValueCursor,
681 nparams: i32,
682) -> i32 {
683 if nparams >= 2
684 && nresults <= 1
685 && arg0.is_number()
686 && unsafe { args.value_unchecked() }.is_number()
687 {
688 let mut r = ((arg0.number_value() as i64) as u32)
689 & ((unsafe { args.value_unchecked() }.number_value() as i64) as u32);
690 for index in 3..=nparams {
691 let arg = unsafe { args.add((index - 2) as usize).value_unchecked() };
692 if !arg.is_number() {
693 return -1;
694 }
695 r &= (arg.number_value() as i64) as u32;
696 }
697 unsafe { result.value_unchecked() }.set_number(r as f64);
698 1
699 } else {
700 -1
701 }
702}
703
704unsafe fn bnot(
706 _thread: &Thread,
707 result: TValueCursor,
708 arg0: TValue,
709 nresults: i32,
710 _args: TValueCursor,
711 nparams: i32,
712) -> i32 {
713 if nparams >= 1 && nresults <= 1 && arg0.is_number() {
714 unsafe { result.value_unchecked() }
715 .set_number((!((arg0.number_value() as i64) as u32)) as f64);
716 1
717 } else {
718 -1
719 }
720}
721
722unsafe fn bor(
724 _thread: &Thread,
725 result: TValueCursor,
726 arg0: TValue,
727 nresults: i32,
728 args: TValueCursor,
729 nparams: i32,
730) -> i32 {
731 if nparams >= 2
732 && nresults <= 1
733 && arg0.is_number()
734 && unsafe { args.value_unchecked() }.is_number()
735 {
736 let mut r = ((arg0.number_value() as i64) as u32)
737 | ((unsafe { args.value_unchecked() }.number_value() as i64) as u32);
738 for index in 3..=nparams {
739 let arg = unsafe { args.add((index - 2) as usize).value_unchecked() };
740 if !arg.is_number() {
741 return -1;
742 }
743 r |= (arg.number_value() as i64) as u32;
744 }
745 unsafe { result.value_unchecked() }.set_number(r as f64);
746 1
747 } else {
748 -1
749 }
750}
751
752unsafe fn bxor(
754 _thread: &Thread,
755 result: TValueCursor,
756 arg0: TValue,
757 nresults: i32,
758 args: TValueCursor,
759 nparams: i32,
760) -> i32 {
761 if nparams >= 2
762 && nresults <= 1
763 && arg0.is_number()
764 && unsafe { args.value_unchecked() }.is_number()
765 {
766 let mut r = ((arg0.number_value() as i64) as u32)
767 ^ ((unsafe { args.value_unchecked() }.number_value() as i64) as u32);
768 for index in 3..=nparams {
769 let arg = unsafe { args.add((index - 2) as usize).value_unchecked() };
770 if !arg.is_number() {
771 return -1;
772 }
773 r ^= (arg.number_value() as i64) as u32;
774 }
775 unsafe { result.value_unchecked() }.set_number(r as f64);
776 1
777 } else {
778 -1
779 }
780}
781
782unsafe fn btest(
784 _thread: &Thread,
785 result: TValueCursor,
786 arg0: TValue,
787 nresults: i32,
788 args: TValueCursor,
789 nparams: i32,
790) -> i32 {
791 if nparams >= 2
792 && nresults <= 1
793 && arg0.is_number()
794 && unsafe { args.value_unchecked() }.is_number()
795 {
796 let mut r = ((arg0.number_value() as i64) as u32)
797 & ((unsafe { args.value_unchecked() }.number_value() as i64) as u32);
798 for index in 3..=nparams {
799 let arg = unsafe { args.add((index - 2) as usize).value_unchecked() };
800 if !arg.is_number() {
801 return -1;
802 }
803 r &= (arg.number_value() as i64) as u32;
804 }
805 unsafe { result.value_unchecked() }.set_boolean(i32::from(r != 0));
806 1
807 } else {
808 -1
809 }
810}
811
812unsafe fn count_lz(
814 _thread: &Thread,
815 result: TValueCursor,
816 arg0: TValue,
817 nresults: i32,
818 _args: TValueCursor,
819 nparams: i32,
820) -> i32 {
821 if nparams >= 1 && nresults <= 1 && arg0.is_number() {
822 let n = (arg0.number_value() as i64) as u32;
823 let r = if n == 0 { 32 } else { n.leading_zeros() };
824 unsafe { result.value_unchecked() }.set_number(r as f64);
825 1
826 } else {
827 -1
828 }
829}
830
831unsafe fn count_rz(
833 _thread: &Thread,
834 result: TValueCursor,
835 arg0: TValue,
836 nresults: i32,
837 _args: TValueCursor,
838 nparams: i32,
839) -> i32 {
840 if nparams >= 1 && nresults <= 1 && arg0.is_number() {
841 let n = (arg0.number_value() as i64) as u32;
842 let r = if n == 0 { 32 } else { n.trailing_zeros() };
843 unsafe { result.value_unchecked() }.set_number(r as f64);
844 1
845 } else {
846 -1
847 }
848}
849
850unsafe fn byte_swap(
852 _thread: &Thread,
853 result: TValueCursor,
854 arg0: TValue,
855 nresults: i32,
856 _args: TValueCursor,
857 nparams: i32,
858) -> i32 {
859 if nparams >= 1 && nresults <= 1 && arg0.is_number() {
860 unsafe { result.value_unchecked() }
861 .set_number(((arg0.number_value() as i64) as u32).swap_bytes() as f64);
862 1
863 } else {
864 -1
865 }
866}
867
868unsafe fn extract(
870 _thread: &Thread,
871 result: TValueCursor,
872 arg0: TValue,
873 nresults: i32,
874 args: TValueCursor,
875 nparams: i32,
876) -> i32 {
877 if nparams >= 2
878 && nresults <= 1
879 && arg0.is_number()
880 && unsafe { args.value_unchecked() }.is_number()
881 {
882 let n = (arg0.number_value() as i64) as u32;
883 let field = unsafe { args.value_unchecked() }.number_value() as i32;
884
885 if nparams == 2 {
886 if (field as u32) < 32 {
887 unsafe { result.value_unchecked() }.set_number(((n >> field) & 1) as f64);
888 return 1;
889 }
890 } else if unsafe { args.add(1).value_unchecked() }.is_number() {
891 let width = unsafe { args.add(1).value_unchecked().number_value() } as i32;
892 if field >= 0 && width > 0 && field + width <= 32 {
893 let mask = !(0xfffffffe_u32 << (width - 1));
894 unsafe { result.value_unchecked() }.set_number(((n >> field) & mask) as f64);
895 return 1;
896 }
897 }
898 }
899 -1
900}
901
902unsafe fn rotate_left(
904 _thread: &Thread,
905 result: TValueCursor,
906 arg0: TValue,
907 nresults: i32,
908 args: TValueCursor,
909 nparams: i32,
910) -> i32 {
911 if nparams >= 2
912 && nresults <= 1
913 && arg0.is_number()
914 && unsafe { args.value_unchecked() }.is_number()
915 {
916 let value = (arg0.number_value() as i64) as u32;
917 let shift = unsafe { args.value_unchecked() }.number_value() as i32;
918 unsafe { result.value_unchecked() }
919 .set_number(value.rotate_left((shift & 31) as u32) as f64);
920 return 1;
921 }
922 -1
923}
924
925unsafe fn shift_left(
927 _thread: &Thread,
928 result: TValueCursor,
929 arg0: TValue,
930 nresults: i32,
931 args: TValueCursor,
932 nparams: i32,
933) -> i32 {
934 if nparams >= 2
935 && nresults <= 1
936 && arg0.is_number()
937 && unsafe { args.value_unchecked() }.is_number()
938 {
939 let value = (arg0.number_value() as i64) as u32;
940 let shift = unsafe { args.value_unchecked() }.number_value() as i32;
941 if (shift as u32) < 32 {
942 unsafe { result.value_unchecked() }.set_number((value << shift) as f64);
943 return 1;
944 }
945 }
946 -1
947}
948
949unsafe fn replace(
951 _thread: &Thread,
952 result: TValueCursor,
953 arg0: TValue,
954 nresults: i32,
955 args: TValueCursor,
956 nparams: i32,
957) -> i32 {
958 unsafe {
959 let field_arg = args.add(1).value_unchecked();
960 if nparams >= 3
961 && nresults <= 1
962 && arg0.is_number()
963 && args.value_unchecked().is_number()
964 && field_arg.is_number()
965 {
966 let number = (arg0.number_value() as i64) as u32;
967 let value = (args.value_unchecked().number_value() as i64) as u32;
968 let field = field_arg.number_value() as i32;
969
970 if nparams == 3 {
971 if (field as u32) < 32 {
972 let mask = 1u32;
973 let replaced = (number & !(mask << field)) | ((value & mask) << field);
974 result.value_unchecked().set_number(replaced as f64);
975 return 1;
976 }
977 } else {
978 let width_arg = args.add(2).value_unchecked();
979 if width_arg.is_number() {
980 let width = width_arg.number_value() as i32;
981 if field >= 0 && width > 0 && field + width <= 32 {
982 let mask = !(0xfffffffe_u32 << (width - 1));
983 let replaced = (number & !(mask << field)) | ((value & mask) << field);
984 result.value_unchecked().set_number(replaced as f64);
985 return 1;
986 }
987 }
988 }
989 }
990 }
991 -1
992}
993
994unsafe fn r_rotate(
996 _thread: &Thread,
997 result: TValueCursor,
998 arg0: TValue,
999 nresults: i32,
1000 args: TValueCursor,
1001 nparams: i32,
1002) -> i32 {
1003 if nparams >= 2
1004 && nresults <= 1
1005 && arg0.is_number()
1006 && unsafe { args.value_unchecked() }.is_number()
1007 {
1008 let value = (arg0.number_value() as i64) as u32;
1009 let shift = unsafe { args.value_unchecked() }.number_value() as i32;
1010 unsafe { result.value_unchecked() }
1011 .set_number(value.rotate_right((shift & 31) as u32) as f64);
1012 return 1;
1013 }
1014 -1
1015}
1016
1017unsafe fn r_shift(
1019 _thread: &Thread,
1020 result: TValueCursor,
1021 arg0: TValue,
1022 nresults: i32,
1023 args: TValueCursor,
1024 nparams: i32,
1025) -> i32 {
1026 if nparams >= 2
1027 && nresults <= 1
1028 && arg0.is_number()
1029 && unsafe { args.value_unchecked() }.is_number()
1030 {
1031 let value = (arg0.number_value() as i64) as u32;
1032 let shift = unsafe { args.value_unchecked() }.number_value() as i32;
1033 if (shift as u32) < 32 {
1034 unsafe { result.value_unchecked() }.set_number((value >> shift) as f64);
1035 return 1;
1036 }
1037 }
1038 -1
1039}
1040
1041unsafe fn extract_k(
1043 _thread: &Thread,
1044 result: TValueCursor,
1045 arg0: TValue,
1046 nresults: i32,
1047 args: TValueCursor,
1048 nparams: i32,
1049) -> i32 {
1050 if nparams >= 2
1051 && nresults <= 1
1052 && arg0.is_number()
1053 && unsafe { args.value_unchecked() }.is_number()
1054 {
1055 let number = (arg0.number_value() as i64) as u32;
1056 let packed = unsafe { args.value_unchecked() }.number_value() as i32;
1057 let field = packed & 31;
1058 let width_minus_one = packed >> 5;
1059 let mask = !(0xfffffffe_u32 << width_minus_one);
1060 unsafe { result.value_unchecked() }.set_number(((number >> field) & mask) as f64);
1061 return 1;
1062 }
1063 -1
1064}
1065
1066unsafe fn byte(
1070 _thread: &Thread,
1071 result: TValueCursor,
1072 arg0: TValue,
1073 nresults: i32,
1074 args: TValueCursor,
1075 nparams: i32,
1076) -> i32 {
1077 if nparams >= 2 && arg0.is_string() && unsafe { args.value_unchecked() }.is_number() {
1078 unsafe {
1079 let string = arg0.string_value();
1080 let start = args.value_unchecked().number_value() as i32;
1081 let end = if nparams >= 3 {
1082 if !args.add(1).value_unchecked().is_number() {
1083 return -1;
1084 }
1085 args.add(1).value_unchecked().number_value() as i32
1086 } else {
1087 start
1088 };
1089
1090 let len = string.as_ptr().as_ref().unwrap_unchecked().len as i32;
1091 if start >= 1 && end >= start && end <= len {
1092 let count = end - start + 1;
1093 let expected = if nresults < 0 { 1 } else { nresults };
1094 if count == expected {
1095 let bytes = string.as_bytes();
1096 for index in 0..count as usize {
1097 result
1098 .add(index)
1099 .value_unchecked()
1100 .set_number(bytes[start as usize + index - 1] as f64);
1101 }
1102 return count;
1103 }
1104 }
1105 }
1106 }
1107 -1
1108}
1109
1110unsafe fn char(
1112 thread: &Thread,
1113 result: TValueCursor,
1114 arg0: TValue,
1115 nresults: i32,
1116 args: TValueCursor,
1117 nparams: i32,
1118) -> i32 {
1119 let mut buffer = [0u8; 8];
1120 if nparams < buffer.len() as i32 && nresults <= 1 {
1121 unsafe {
1122 if thread.needs_gc() {
1123 return -1;
1124 }
1125
1126 if nparams >= 1 {
1127 if !arg0.is_number() {
1128 return -1;
1129 }
1130 let ch = arg0.number_value() as i32;
1131 if (ch as u8) as i32 != ch {
1132 return -1;
1133 }
1134 buffer[0] = ch as u8;
1135 }
1136
1137 for index in 2..=nparams {
1138 let arg = args.add((index - 2) as usize);
1139 if !arg.value_unchecked().is_number() {
1140 return -1;
1141 }
1142 let ch = arg.value_unchecked().number_value() as i32;
1143 if (ch as u8) as i32 != ch {
1144 return -1;
1145 }
1146 buffer[index as usize - 1] = ch as u8;
1147 }
1148
1149 buffer[nparams as usize] = 0;
1150 let Ok(string) = thread.intern_string(buffer[..nparams as usize].as_bstr()) else {
1151 return -1;
1152 };
1153 result.value_unchecked().set_string_value(string);
1154 }
1155 return 1;
1156 }
1157
1158 -1
1159}
1160
1161unsafe fn sub(
1163 thread: &Thread,
1164 result: TValueCursor,
1165 arg0: TValue,
1166 nresults: i32,
1167 args: TValueCursor,
1168 nparams: i32,
1169) -> i32 {
1170 unsafe {
1171 if nparams >= 3
1172 && nresults <= 1
1173 && arg0.is_string()
1174 && args.value_unchecked().is_number()
1175 && args.add(1).value_unchecked().is_number()
1176 {
1177 if thread.needs_gc() {
1178 return -1;
1179 }
1180
1181 let string = arg0.string_value();
1182 let start = args.value_unchecked().number_value() as i32;
1183 let end = args.add(1).value_unchecked().number_value() as i32;
1184 let len = string.as_ptr().as_ref().unwrap_unchecked().len as i32;
1185
1186 if start >= 1 && end >= start && ((end - 1) as u32) < (len as u32) {
1187 let bytes = string.as_bytes();
1188 let Ok(slice) =
1189 thread.intern_string(bytes[(start - 1) as usize..end as usize].as_bstr())
1190 else {
1191 return -1;
1192 };
1193 result.value_unchecked().set_string_value(slice);
1194 return 1;
1195 }
1196 }
1197
1198 -1
1199 }
1200}
1201
1202unsafe fn raw_equal(
1205 _thread: &Thread,
1206 result: TValueCursor,
1207 arg0: TValue,
1208 nresults: i32,
1209 args: TValueCursor,
1210 nparams: i32,
1211) -> i32 {
1212 if nparams >= 2 && nresults <= 1 {
1213 unsafe { result.value_unchecked() }
1214 .set_boolean(i32::from(arg0.raw_equal(unsafe { args.value_unchecked() })));
1215 1
1216 } else {
1217 -1
1218 }
1219}
1220
1221unsafe fn raw_get(
1223 _thread: &Thread,
1224 result: TValueCursor,
1225 arg0: TValue,
1226 nresults: i32,
1227 args: TValueCursor,
1228 nparams: i32,
1229) -> i32 {
1230 if nparams >= 2 && nresults <= 1 && arg0.is_table() {
1231 unsafe { result.value_unchecked() }
1232 .set_obj(unsafe { arg0.table_value().get(args.value_unchecked()) });
1233 1
1234 } else {
1235 -1
1236 }
1237}
1238
1239unsafe fn raw_set(
1241 thread: &Thread,
1242 result: TValueCursor,
1243 arg0: TValue,
1244 nresults: i32,
1245 args: TValueCursor,
1246 nparams: i32,
1247) -> i32 {
1248 if nparams >= 3 && nresults <= 1 && arg0.is_table() {
1249 unsafe {
1250 let key = args;
1251 let key_value = key.value_unchecked();
1252 if key_value.is_nil()
1253 || (key_value.is_number() && key_value.number_value().is_nan())
1254 || (key_value.is_vector() && key_value.vector_value().iter().any(|v| v.is_nan()))
1255 {
1256 return -1;
1257 }
1258
1259 let table = arg0.table_value();
1260 if table.as_ptr().as_ref().unwrap_unchecked().readonly != 0 {
1261 return -1;
1262 }
1263
1264 result.value_unchecked().set_obj(arg0);
1265 let Ok(slot) = thread.set(table, key_value) else {
1266 return -1;
1267 };
1268 let value = args.add(1);
1269 slot.set_obj(value.value_unchecked());
1270 if value.value_unchecked().is_collectable() {
1271 let child = value.value_unchecked().gc_value();
1272 let table_object: GcObject = table.into();
1273 if table_object.is_black() && child.is_white() {
1274 thread.barrier_table(table, child);
1275 }
1276 }
1277 1
1278 }
1279 } else {
1280 -1
1281 }
1282}
1283
1284unsafe fn t_insert(
1286 thread: &Thread,
1287 _result: TValueCursor,
1288 arg0: TValue,
1289 nresults: i32,
1290 args: TValueCursor,
1291 nparams: i32,
1292) -> i32 {
1293 if nparams == 2 && nresults <= 0 && arg0.is_table() {
1294 unsafe {
1295 let table = arg0.table_value();
1296 if table.as_ptr().as_ref().unwrap_unchecked().readonly != 0 {
1297 return -1;
1298 }
1299
1300 let pos = table.getn() + 1;
1301 let slot = if let Some(slot) = table.array_slot_for_key(pos) {
1302 slot
1303 } else {
1304 let Ok(slot) = thread.set_num(table, pos) else {
1305 return -1;
1306 };
1307 slot
1308 };
1309 let value = args.value_unchecked();
1310 slot.set_obj(value);
1311 if value.is_collectable() {
1312 let child = value.gc_value();
1313 let table_object: GcObject = table.into();
1314 if table_object.is_black() && child.is_white() {
1315 thread.barrier_table(table, child);
1316 }
1317 }
1318 0
1319 }
1320 } else {
1321 -1
1322 }
1323}
1324
1325unsafe fn t_unpack(
1327 thread: &Thread,
1328 result: TValueCursor,
1329 arg0: TValue,
1330 nresults: i32,
1331 args: TValueCursor,
1332 nparams: i32,
1333) -> i32 {
1334 if nparams >= 1 && nresults < 0 && arg0.is_table() {
1335 unsafe {
1336 let table = arg0.table_value();
1337 let mut n = -1;
1338 if nparams == 1 {
1339 n = table.getn();
1340 } else if nparams == 3
1341 && args.value_unchecked().is_number()
1342 && args.add(1).value_unchecked().is_number()
1343 && args.value_unchecked().number_value() == 1.0
1344 {
1345 n = args.add(1).value_unchecked().number_value() as i32;
1346 }
1347
1348 let stack_last = thread.stack_last();
1349 let stack_room = stack_last.offset_from(result) as i32;
1350 if n >= 0
1351 && n <= table.as_ptr().as_ref().unwrap_unchecked().size_array
1352 && stack_room >= n
1353 && n + nparams <= 8000
1354 {
1355 let array = table.array_cursor();
1356 for index in 0..n as usize {
1357 result
1358 .add(index)
1359 .value_unchecked()
1360 .set_obj(array.add(index).value_unchecked());
1361 }
1362 thread.expand_stack_limit(result.add(n as usize));
1363 return n;
1364 }
1365 }
1366 }
1367 -1
1368}
1369
1370unsafe fn raw_len(
1372 _thread: &Thread,
1373 result: TValueCursor,
1374 arg0: TValue,
1375 nresults: i32,
1376 _args: TValueCursor,
1377 nparams: i32,
1378) -> i32 {
1379 if nparams >= 1 && nresults <= 1 {
1380 if arg0.is_table() {
1381 unsafe { result.value_unchecked() }
1382 .set_number(unsafe { arg0.table_value().getn() as f64 });
1383 return 1;
1384 } else if arg0.is_string() {
1385 unsafe { result.value_unchecked() }.set_number(unsafe {
1386 arg0.string_value().as_ptr().as_ref().unwrap_unchecked().len as f64
1387 });
1388 return 1;
1389 }
1390 }
1391 -1
1392}
1393
1394unsafe fn get_metatable(
1396 thread: &Thread,
1397 result: TValueCursor,
1398 arg0: TValue,
1399 nresults: i32,
1400 _args: TValueCursor,
1401 nparams: i32,
1402) -> i32 {
1403 if nparams >= 1 && nresults <= 1 {
1404 let (mt, mtv) = unsafe {
1405 match arg0.tt() {
1406 x if x == LUA_TTABLE => arg0.table_value().metatable(),
1407 x if x == LUA_TUSERDATA => arg0.userdata_value().metatable(),
1408 tag => thread.global().metatable(tag as usize),
1409 }
1410 .map_or_else(
1411 || (None, crate::value::nil_object()),
1412 |mt: Table| {
1413 let name = thread.global().tm_name(TmEvent::MetaTable as usize);
1414 (Some(mt), mt.get_str(name))
1415 },
1416 )
1417 };
1418
1419 if !mtv.is_nil() {
1420 unsafe { result.value_unchecked() }.set_obj(mtv);
1421 } else if let Some(mt) = mt {
1422 unsafe { result.value_unchecked() }.set_table_value(mt);
1423 } else {
1424 unsafe { result.value_unchecked() }.set_nil();
1425 }
1426 return 1;
1427 }
1428 -1
1429}
1430
1431unsafe fn set_metatable(
1433 thread: &Thread,
1434 result: TValueCursor,
1435 arg0: TValue,
1436 nresults: i32,
1437 args: TValueCursor,
1438 nparams: i32,
1439) -> i32 {
1440 unsafe {
1441 if nparams >= 2 && nresults <= 1 && arg0.is_table() && args.value_unchecked().is_table() {
1442 let table = arg0.table_value();
1443 if table.as_ptr().as_ref().unwrap_unchecked().readonly != 0
1444 || table.metatable().is_some()
1445 {
1446 return -1;
1447 }
1448
1449 let mt = args.value_unchecked().table_value();
1450 table.set_metatable(Some(mt));
1451 let object: GcObject = table.into();
1452 let child: GcObject = mt.into();
1453 if object.is_black() && child.is_white() {
1454 thread.barrier_forward(object, child);
1455 }
1456 result.value_unchecked().set_table_value(table);
1457 return 1;
1458 }
1459 }
1460 -1
1461}
1462
1463unsafe fn set_vector(result: TValueCursor, x: f32, y: f32, z: f32, w: f32) {
1466 #[cfg(feature = "vector4")]
1467 unsafe { result.value_unchecked() }.set_vector([x, y, z, w]);
1468
1469 #[cfg(not(feature = "vector4"))]
1470 let _ = w;
1471 #[cfg(not(feature = "vector4"))]
1472 unsafe { result.value_unchecked() }.set_vector([x, y, z]);
1473}
1474
1475unsafe fn vector(
1477 _thread: &Thread,
1478 result: TValueCursor,
1479 arg0: TValue,
1480 nresults: i32,
1481 args: TValueCursor,
1482 nparams: i32,
1483) -> i32 {
1484 unsafe {
1485 if nparams >= 2 && nresults <= 1 && arg0.is_number() && args.value_unchecked().is_number() {
1486 let x = arg0.number_value() as f32;
1487 let y = args.value_unchecked().number_value() as f32;
1488 let mut z = 0.0f32;
1489 if nparams >= 3 {
1490 if !args.add(1).value_unchecked().is_number() {
1491 return -1;
1492 }
1493 z = args.add(1).value_unchecked().number_value() as f32;
1494 }
1495 #[cfg(feature = "vector4")]
1496 {
1497 let mut w = 0.0f32;
1498 if nparams >= 4 {
1499 if !args.add(2).value_unchecked().is_number() {
1500 return -1;
1501 }
1502 w = args.add(2).value_unchecked().number_value() as f32;
1503 }
1504 set_vector(result, x, y, z, w);
1505 }
1506 #[cfg(not(feature = "vector4"))]
1507 {
1508 set_vector(result, x, y, z, 0.0);
1509 }
1510 1
1511 } else {
1512 -1
1513 }
1514 }
1515}
1516
1517unsafe fn vector_magnitude(
1519 _thread: &Thread,
1520 result: TValueCursor,
1521 arg0: TValue,
1522 nresults: i32,
1523 _args: TValueCursor,
1524 nparams: i32,
1525) -> i32 {
1526 if nparams >= 1 && nresults <= 1 && arg0.is_vector() {
1527 let vector = arg0.vector_value();
1528 let mut sum = 0.0f32;
1529 for value in vector {
1530 sum += value * value;
1531 }
1532 unsafe { result.value_unchecked() }.set_number(sum.sqrt() as f64);
1533 return 1;
1534 }
1535 -1
1536}
1537
1538unsafe fn vector_normalize(
1540 _thread: &Thread,
1541 result: TValueCursor,
1542 arg0: TValue,
1543 nresults: i32,
1544 _args: TValueCursor,
1545 nparams: i32,
1546) -> i32 {
1547 if nparams >= 1 && nresults <= 1 && arg0.is_vector() {
1548 let vector = arg0.vector_value();
1549 let mut sum = 0.0f32;
1550 for value in vector {
1551 sum += value * value;
1552 }
1553 let inv_sqrt = 1.0f32 / sum.sqrt();
1554 #[cfg(feature = "vector4")]
1555 unsafe {
1556 set_vector(
1557 result,
1558 vector[0] * inv_sqrt,
1559 vector[1] * inv_sqrt,
1560 vector[2] * inv_sqrt,
1561 vector[3] * inv_sqrt,
1562 );
1563 }
1564 #[cfg(not(feature = "vector4"))]
1565 unsafe {
1566 set_vector(
1567 result,
1568 vector[0] * inv_sqrt,
1569 vector[1] * inv_sqrt,
1570 vector[2] * inv_sqrt,
1571 0.0,
1572 );
1573 }
1574 return 1;
1575 }
1576 -1
1577}
1578
1579unsafe fn vector_cross(
1581 _thread: &Thread,
1582 result: TValueCursor,
1583 arg0: TValue,
1584 nresults: i32,
1585 args: TValueCursor,
1586 nparams: i32,
1587) -> i32 {
1588 if nparams >= 2
1589 && nresults <= 1
1590 && arg0.is_vector()
1591 && unsafe { args.value_unchecked() }.is_vector()
1592 {
1593 let a = arg0.vector_value();
1594 let b = unsafe { args.value_unchecked() }.vector_value();
1595 unsafe {
1596 set_vector(
1597 result,
1598 a[1] * b[2] - a[2] * b[1],
1599 a[2] * b[0] - a[0] * b[2],
1600 a[0] * b[1] - a[1] * b[0],
1601 0.0,
1602 );
1603 }
1604 return 1;
1605 }
1606 -1
1607}
1608
1609unsafe fn vector_dot(
1611 _thread: &Thread,
1612 result: TValueCursor,
1613 arg0: TValue,
1614 nresults: i32,
1615 args: TValueCursor,
1616 nparams: i32,
1617) -> i32 {
1618 if nparams >= 2
1619 && nresults <= 1
1620 && arg0.is_vector()
1621 && unsafe { args.value_unchecked() }.is_vector()
1622 {
1623 let a = arg0.vector_value();
1624 let b = unsafe { args.value_unchecked() }.vector_value();
1625 let mut dot = 0.0f32;
1626 for (left, right) in a.iter().zip(b.iter()) {
1627 dot += left * right;
1628 }
1629 unsafe { result.value_unchecked() }.set_number(dot as f64);
1630 return 1;
1631 }
1632 -1
1633}
1634
1635macro_rules! unary_vector {
1636 ($doc:literal, $name:ident, $op:expr) => {
1637 #[doc = $doc]
1638 unsafe fn $name(
1639 _thread: &Thread,
1640 result: TValueCursor,
1641 arg0: TValue,
1642 nresults: i32,
1643 _args: TValueCursor,
1644 nparams: i32,
1645 ) -> i32 {
1646 if nparams >= 1 && nresults <= 1 && arg0.is_vector() {
1647 let vector = arg0.vector_value();
1648 #[cfg(feature = "vector4")]
1649 unsafe {
1650 set_vector(
1651 result,
1652 ($op)(vector[0]),
1653 ($op)(vector[1]),
1654 ($op)(vector[2]),
1655 ($op)(vector[3]),
1656 );
1657 }
1658 #[cfg(not(feature = "vector4"))]
1659 unsafe {
1660 set_vector(
1661 result,
1662 ($op)(vector[0]),
1663 ($op)(vector[1]),
1664 ($op)(vector[2]),
1665 0.0,
1666 );
1667 }
1668 return 1;
1669 }
1670 -1
1671 }
1672 };
1673}
1674
1675unary_vector!("`luauF_vectorfloor`", vector_floor, f32::floor);
1676unary_vector!("`luauF_vectorceil`", vector_ceil, f32::ceil);
1677unary_vector!("`luauF_vectorabs`", vector_abs, f32::abs);
1678unary_vector!("`luauF_vectorsign`", vector_sign, sign_f);
1679
1680unsafe fn vector_clamp(
1682 _thread: &Thread,
1683 result: TValueCursor,
1684 arg0: TValue,
1685 nresults: i32,
1686 args: TValueCursor,
1687 nparams: i32,
1688) -> i32 {
1689 unsafe {
1690 let max_arg = args.add(1).value_unchecked();
1691 if nparams >= 3
1692 && nresults <= 1
1693 && arg0.is_vector()
1694 && args.value_unchecked().is_vector()
1695 && max_arg.is_vector()
1696 {
1697 let value = arg0.vector_value();
1698 let min = args.value_unchecked().vector_value();
1699 let max = max_arg.vector_value();
1700 if min[0] <= max[0] && min[1] <= max[1] && min[2] <= max[2] {
1701 #[cfg(feature = "vector4")]
1702 set_vector(
1703 result,
1704 clamp_f(value[0], min[0], max[0]),
1705 clamp_f(value[1], min[1], max[1]),
1706 clamp_f(value[2], min[2], max[2]),
1707 clamp_f(value[3], min[3], max[3]),
1708 );
1709 #[cfg(not(feature = "vector4"))]
1710 set_vector(
1711 result,
1712 clamp_f(value[0], min[0], max[0]),
1713 clamp_f(value[1], min[1], max[1]),
1714 clamp_f(value[2], min[2], max[2]),
1715 0.0,
1716 );
1717 return 1;
1718 }
1719 }
1720 }
1721 -1
1722}
1723
1724unsafe fn vector_min(
1726 _thread: &Thread,
1727 result: TValueCursor,
1728 arg0: TValue,
1729 nresults: i32,
1730 args: TValueCursor,
1731 nparams: i32,
1732) -> i32 {
1733 unsafe {
1734 if nparams >= 2 && nresults <= 1 && arg0.is_vector() && args.value_unchecked().is_vector() {
1735 let mut value = arg0.vector_value();
1736 let other = args.value_unchecked().vector_value();
1737 for (slot, candidate) in value.iter_mut().zip(other.iter()) {
1738 if *candidate < *slot {
1739 *slot = *candidate;
1740 }
1741 }
1742 for index in 3..=nparams {
1743 let arg = args.add((index - 2) as usize).value_unchecked();
1744 if !arg.is_vector() {
1745 return -1;
1746 }
1747 let candidate = arg.vector_value();
1748 for (slot, candidate) in value.iter_mut().zip(candidate.iter()) {
1749 if *candidate < *slot {
1750 *slot = *candidate;
1751 }
1752 }
1753 }
1754 #[cfg(feature = "vector4")]
1755 set_vector(result, value[0], value[1], value[2], value[3]);
1756 #[cfg(not(feature = "vector4"))]
1757 set_vector(result, value[0], value[1], value[2], 0.0);
1758 return 1;
1759 }
1760 }
1761 -1
1762}
1763
1764unsafe fn vector_max(
1766 _thread: &Thread,
1767 result: TValueCursor,
1768 arg0: TValue,
1769 nresults: i32,
1770 args: TValueCursor,
1771 nparams: i32,
1772) -> i32 {
1773 unsafe {
1774 if nparams >= 2 && nresults <= 1 && arg0.is_vector() && args.value_unchecked().is_vector() {
1775 let mut value = arg0.vector_value();
1776 let other = args.value_unchecked().vector_value();
1777 for (slot, candidate) in value.iter_mut().zip(other.iter()) {
1778 if *candidate > *slot {
1779 *slot = *candidate;
1780 }
1781 }
1782 for index in 3..=nparams {
1783 let arg = args.add((index - 2) as usize).value_unchecked();
1784 if !arg.is_vector() {
1785 return -1;
1786 }
1787 let candidate = arg.vector_value();
1788 for (slot, candidate) in value.iter_mut().zip(candidate.iter()) {
1789 if *candidate > *slot {
1790 *slot = *candidate;
1791 }
1792 }
1793 }
1794 #[cfg(feature = "vector4")]
1795 set_vector(result, value[0], value[1], value[2], value[3]);
1796 #[cfg(not(feature = "vector4"))]
1797 set_vector(result, value[0], value[1], value[2], 0.0);
1798 return 1;
1799 }
1800 }
1801 -1
1802}
1803
1804unsafe fn lerp(
1806 _thread: &Thread,
1807 result: TValueCursor,
1808 arg0: TValue,
1809 nresults: i32,
1810 args: TValueCursor,
1811 nparams: i32,
1812) -> i32 {
1813 if nparams >= 3
1814 && nresults <= 1
1815 && arg0.is_number()
1816 && unsafe { args.value_unchecked() }.is_number()
1817 && unsafe { args.add(1).value_unchecked() }.is_number()
1818 {
1819 let a = arg0.number_value();
1820 let b = unsafe { args.value_unchecked() }.number_value();
1821 let t = unsafe { args.add(1).value_unchecked() }.number_value();
1822 let value = if t == 1.0 { b } else { a + (b - a) * t };
1823 unsafe { result.value_unchecked() }.set_number(value);
1824 return 1;
1825 }
1826 -1
1827}
1828
1829unsafe fn vector_lerp(
1831 _thread: &Thread,
1832 result: TValueCursor,
1833 arg0: TValue,
1834 nresults: i32,
1835 args: TValueCursor,
1836 nparams: i32,
1837) -> i32 {
1838 unsafe {
1839 let t_arg = args.add(1).value_unchecked();
1840 if nparams >= 3
1841 && nresults <= 1
1842 && arg0.is_vector()
1843 && args.value_unchecked().is_vector()
1844 && t_arg.is_number()
1845 {
1846 let a = arg0.vector_value();
1847 let b = args.value_unchecked().vector_value();
1848 let t = t_arg.number_value() as f32;
1849 #[cfg(feature = "vector4")]
1850 set_vector(
1851 result,
1852 lerp_f(a[0], b[0], t),
1853 lerp_f(a[1], b[1], t),
1854 lerp_f(a[2], b[2], t),
1855 lerp_f(a[3], b[3], t),
1856 );
1857 #[cfg(not(feature = "vector4"))]
1858 set_vector(
1859 result,
1860 lerp_f(a[0], b[0], t),
1861 lerp_f(a[1], b[1], t),
1862 lerp_f(a[2], b[2], t),
1863 0.0,
1864 );
1865 return 1;
1866 }
1867 }
1868 -1
1869}
1870
1871macro_rules! unary_int {
1874 ($doc:literal, $name:ident, $op:expr) => {
1875 #[doc = $doc]
1876 unsafe fn $name(
1877 _thread: &Thread,
1878 result: TValueCursor,
1879 arg0: TValue,
1880 nresults: i32,
1881 _args: TValueCursor,
1882 nparams: i32,
1883 ) -> i32 {
1884 if nparams >= 1 && nresults <= 1 && arg0.is_integer() {
1885 unsafe { result.value_unchecked() }.set_integer(($op)(arg0.integer_value()));
1886 1
1887 } else {
1888 -1
1889 }
1890 }
1891 };
1892}
1893
1894macro_rules! binary_int {
1895 ($doc:literal, $name:ident, $op:expr) => {
1896 #[doc = $doc]
1897 unsafe fn $name(
1898 _thread: &Thread,
1899 result: TValueCursor,
1900 arg0: TValue,
1901 nresults: i32,
1902 args: TValueCursor,
1903 nparams: i32,
1904 ) -> i32 {
1905 if nparams >= 2
1906 && nresults <= 1
1907 && arg0.is_integer()
1908 && unsafe { args.value_unchecked() }.is_integer()
1909 {
1910 unsafe { result.value_unchecked() }.set_integer(($op)(
1911 arg0.integer_value(),
1912 unsafe { args.value_unchecked() }.integer_value(),
1913 ));
1914 1
1915 } else {
1916 -1
1917 }
1918 }
1919 };
1920}
1921
1922unary_int!(
1923 "`luauF_integer_neg`",
1924 integer_neg,
1925 |a: i64| (!(a as u64)).wrapping_add(1) as i64
1926);
1927binary_int!("`luauF_integer_add`", integer_add, |a: i64, b: i64| {
1928 ((a as u64).wrapping_add(b as u64)) as i64
1929});
1930binary_int!("`luauF_integer_sub`", integer_sub, |a: i64, b: i64| {
1931 ((a as u64).wrapping_sub(b as u64)) as i64
1932});
1933binary_int!("`luauF_integer_mul`", integer_mul, |a: i64, b: i64| {
1934 ((a as u64).wrapping_mul(b as u64)) as i64
1935});
1936
1937unsafe fn integer_to_number(
1939 _thread: &Thread,
1940 result: TValueCursor,
1941 arg0: TValue,
1942 nresults: i32,
1943 _args: TValueCursor,
1944 nparams: i32,
1945) -> i32 {
1946 if nparams >= 1 && nresults <= 1 && arg0.is_integer() {
1947 unsafe { result.value_unchecked() }.set_number(arg0.integer_value() as f64);
1948 return 1;
1949 }
1950 -1
1951}
1952
1953macro_rules! binary_integer_predicate {
1954 ($doc:literal, $name:ident, $left:expr, $right:expr, $pred:expr) => {
1955 #[doc = $doc]
1956 unsafe fn $name(
1957 _thread: &Thread,
1958 result: TValueCursor,
1959 arg0: TValue,
1960 nresults: i32,
1961 args: TValueCursor,
1962 nparams: i32,
1963 ) -> i32 {
1964 if nparams >= 2
1965 && nresults <= 1
1966 && arg0.is_integer()
1967 && unsafe { args.value_unchecked() }.is_integer()
1968 {
1969 let left = $left(arg0.integer_value());
1970 let right = $right(unsafe { args.value_unchecked() }.integer_value());
1971 unsafe { result.value_unchecked() }.set_boolean(i32::from(($pred)(left, right)));
1972 return 1;
1973 }
1974 -1
1975 }
1976 };
1977}
1978
1979binary_integer_predicate!(
1980 "`luauF_integerlt`",
1981 integer_lt,
1982 |value: i64| value,
1983 |value: i64| value,
1984 |a, b| a < b
1985);
1986binary_integer_predicate!(
1987 "`luauF_integerle`",
1988 integer_le,
1989 |value: i64| value,
1990 |value: i64| value,
1991 |a, b| a <= b
1992);
1993binary_integer_predicate!(
1994 "`luauF_integergt`",
1995 integer_gt,
1996 |value: i64| value,
1997 |value: i64| value,
1998 |a, b| a > b
1999);
2000binary_integer_predicate!(
2001 "`luauF_integerge`",
2002 integer_ge,
2003 |value: i64| value,
2004 |value: i64| value,
2005 |a, b| a >= b
2006);
2007binary_integer_predicate!(
2008 "`luauF_integerult`",
2009 integer_ult,
2010 |value: i64| value as u64,
2011 |value: i64| value as u64,
2012 |a, b| a < b
2013);
2014binary_integer_predicate!(
2015 "`luauF_integerule`",
2016 integer_ule,
2017 |value: i64| value as u64,
2018 |value: i64| value as u64,
2019 |a, b| a <= b
2020);
2021binary_integer_predicate!(
2022 "`luauF_integerugt`",
2023 integer_ugt,
2024 |value: i64| value as u64,
2025 |value: i64| value as u64,
2026 |a, b| a > b
2027);
2028binary_integer_predicate!(
2029 "`luauF_integeruge`",
2030 integer_uge,
2031 |value: i64| value as u64,
2032 |value: i64| value as u64,
2033 |a, b| a >= b
2034);
2035
2036unsafe fn integer_create(
2038 _thread: &Thread,
2039 result: TValueCursor,
2040 arg0: TValue,
2041 nresults: i32,
2042 _args: TValueCursor,
2043 nparams: i32,
2044) -> i32 {
2045 if nparams >= 1 && nresults <= 1 && arg0.is_number() {
2046 let value = arg0.number_value();
2047 if (i64::MIN as f64) <= value && value < 9223372036854775808.0 {
2048 let integer = value as i64;
2049 if integer as f64 == value {
2050 unsafe { result.value_unchecked() }.set_integer(integer);
2051 return 1;
2052 }
2053 }
2054 unsafe { result.value_unchecked() }.set_nil();
2055 return 1;
2056 }
2057 -1
2058}
2059
2060unsafe fn integer_div(
2062 _thread: &Thread,
2063 result: TValueCursor,
2064 arg0: TValue,
2065 nresults: i32,
2066 args: TValueCursor,
2067 nparams: i32,
2068) -> i32 {
2069 if nparams >= 2
2070 && nresults <= 1
2071 && arg0.is_integer()
2072 && unsafe { args.value_unchecked() }.is_integer()
2073 {
2074 let a = arg0.integer_value();
2075 let b = unsafe { args.value_unchecked() }.integer_value();
2076 if b == 0 || (a == i64::MIN && b == -1) {
2077 return -1;
2078 }
2079 unsafe { result.value_unchecked() }.set_integer(a / b);
2080 return 1;
2081 }
2082 -1
2083}
2084
2085unsafe fn integer_udiv(
2087 _thread: &Thread,
2088 result: TValueCursor,
2089 arg0: TValue,
2090 nresults: i32,
2091 args: TValueCursor,
2092 nparams: i32,
2093) -> i32 {
2094 if nparams >= 2
2095 && nresults <= 1
2096 && arg0.is_integer()
2097 && unsafe { args.value_unchecked() }.is_integer()
2098 {
2099 let a = arg0.integer_value() as u64;
2100 let b = unsafe { args.value_unchecked() }.integer_value() as u64;
2101 if b == 0 {
2102 return -1;
2103 }
2104 unsafe { result.value_unchecked() }.set_integer((a / b) as i64);
2105 return 1;
2106 }
2107 -1
2108}
2109
2110unsafe fn integer_band(
2112 _thread: &Thread,
2113 result: TValueCursor,
2114 arg0: TValue,
2115 nresults: i32,
2116 args: TValueCursor,
2117 nparams: i32,
2118) -> i32 {
2119 if nparams >= 1 && nresults <= 1 && arg0.is_integer() {
2120 let mut value = arg0.integer_value() as u64;
2121 for index in 2..=nparams {
2122 let arg = unsafe { args.add((index - 2) as usize).value_unchecked() };
2123 if !arg.is_integer() {
2124 return -1;
2125 }
2126 value &= arg.integer_value() as u64;
2127 }
2128 unsafe { result.value_unchecked() }.set_integer(value as i64);
2129 return 1;
2130 }
2131 -1
2132}
2133
2134unsafe fn integer_bor(
2136 _thread: &Thread,
2137 result: TValueCursor,
2138 arg0: TValue,
2139 nresults: i32,
2140 args: TValueCursor,
2141 nparams: i32,
2142) -> i32 {
2143 if nparams >= 1 && nresults <= 1 && arg0.is_integer() {
2144 let mut value = arg0.integer_value() as u64;
2145 for index in 2..=nparams {
2146 let arg = unsafe { args.add((index - 2) as usize).value_unchecked() };
2147 if !arg.is_integer() {
2148 return -1;
2149 }
2150 value |= arg.integer_value() as u64;
2151 }
2152 unsafe { result.value_unchecked() }.set_integer(value as i64);
2153 return 1;
2154 }
2155 -1
2156}
2157
2158unsafe fn integer_bxor(
2160 _thread: &Thread,
2161 result: TValueCursor,
2162 arg0: TValue,
2163 nresults: i32,
2164 args: TValueCursor,
2165 nparams: i32,
2166) -> i32 {
2167 if nparams >= 1 && nresults <= 1 && arg0.is_integer() {
2168 let mut value = arg0.integer_value() as u64;
2169 for index in 2..=nparams {
2170 let arg = unsafe { args.add((index - 2) as usize).value_unchecked() };
2171 if !arg.is_integer() {
2172 return -1;
2173 }
2174 value ^= arg.integer_value() as u64;
2175 }
2176 unsafe { result.value_unchecked() }.set_integer(value as i64);
2177 return 1;
2178 }
2179 -1
2180}
2181
2182unary_int!("`luauF_integerbnot`", integer_bnot, |a: i64| !(a as u64)
2183 as i64);
2184
2185unsafe fn integer_byte_swap(
2187 _thread: &Thread,
2188 result: TValueCursor,
2189 arg0: TValue,
2190 nresults: i32,
2191 _args: TValueCursor,
2192 nparams: i32,
2193) -> i32 {
2194 if nparams >= 1 && nresults <= 1 && arg0.is_integer() {
2195 unsafe { result.value_unchecked() }
2196 .set_integer((arg0.integer_value() as u64).swap_bytes() as i64);
2197 return 1;
2198 }
2199 -1
2200}
2201
2202unsafe fn integer_btest(
2204 _thread: &Thread,
2205 result: TValueCursor,
2206 arg0: TValue,
2207 nresults: i32,
2208 args: TValueCursor,
2209 nparams: i32,
2210) -> i32 {
2211 if nparams >= 1 && nresults <= 1 && arg0.is_integer() {
2212 let mut value = arg0.integer_value() as u64;
2213 for index in 2..=nparams {
2214 let arg = unsafe { args.add((index - 2) as usize).value_unchecked() };
2215 if !arg.is_integer() {
2216 return -1;
2217 }
2218 value &= arg.integer_value() as u64;
2219 }
2220 unsafe { result.value_unchecked() }.set_boolean(i32::from(value != 0));
2221 return 1;
2222 }
2223 -1
2224}
2225
2226unsafe fn integer_min(
2228 _thread: &Thread,
2229 result: TValueCursor,
2230 arg0: TValue,
2231 nresults: i32,
2232 args: TValueCursor,
2233 nparams: i32,
2234) -> i32 {
2235 if nparams >= 2
2236 && nresults <= 1
2237 && arg0.is_integer()
2238 && unsafe { args.value_unchecked() }.is_integer()
2239 {
2240 let mut value = arg0
2241 .integer_value()
2242 .min(unsafe { args.value_unchecked() }.integer_value());
2243 for index in 3..=nparams {
2244 let arg = unsafe { args.add((index - 2) as usize).value_unchecked() };
2245 if !arg.is_integer() {
2246 return -1;
2247 }
2248 value = value.min(arg.integer_value());
2249 }
2250 unsafe { result.value_unchecked() }.set_integer(value);
2251 return 1;
2252 }
2253 -1
2254}
2255
2256unsafe fn integer_max(
2258 _thread: &Thread,
2259 result: TValueCursor,
2260 arg0: TValue,
2261 nresults: i32,
2262 args: TValueCursor,
2263 nparams: i32,
2264) -> i32 {
2265 if nparams >= 2
2266 && nresults <= 1
2267 && arg0.is_integer()
2268 && unsafe { args.value_unchecked() }.is_integer()
2269 {
2270 let mut value = arg0
2271 .integer_value()
2272 .max(unsafe { args.value_unchecked() }.integer_value());
2273 for index in 3..=nparams {
2274 let arg = unsafe { args.add((index - 2) as usize).value_unchecked() };
2275 if !arg.is_integer() {
2276 return -1;
2277 }
2278 value = value.max(arg.integer_value());
2279 }
2280 unsafe { result.value_unchecked() }.set_integer(value);
2281 return 1;
2282 }
2283 -1
2284}
2285
2286unsafe fn integer_rem(
2288 _thread: &Thread,
2289 result: TValueCursor,
2290 arg0: TValue,
2291 nresults: i32,
2292 args: TValueCursor,
2293 nparams: i32,
2294) -> i32 {
2295 if nparams >= 2
2296 && nresults <= 1
2297 && arg0.is_integer()
2298 && unsafe { args.value_unchecked() }.is_integer()
2299 {
2300 let a = arg0.integer_value();
2301 let b = unsafe { args.value_unchecked() }.integer_value();
2302 if b == 0 {
2303 return -1;
2304 }
2305 let value = if a == i64::MIN && b == -1 { 0 } else { a % b };
2306 unsafe { result.value_unchecked() }.set_integer(value);
2307 return 1;
2308 }
2309 -1
2310}
2311
2312unsafe fn integer_idiv(
2314 _thread: &Thread,
2315 result: TValueCursor,
2316 arg0: TValue,
2317 nresults: i32,
2318 args: TValueCursor,
2319 nparams: i32,
2320) -> i32 {
2321 if nparams >= 2
2322 && nresults <= 1
2323 && arg0.is_integer()
2324 && unsafe { args.value_unchecked() }.is_integer()
2325 {
2326 let a = arg0.integer_value();
2327 let b = unsafe { args.value_unchecked() }.integer_value();
2328 if b == 0 || (a == i64::MIN && b == -1) {
2329 return -1;
2330 }
2331 let quotient = a / b;
2332 let value = if quotient < 0 && a % b != 0 {
2333 quotient - 1
2334 } else {
2335 quotient
2336 };
2337 unsafe { result.value_unchecked() }.set_integer(value);
2338 return 1;
2339 }
2340 -1
2341}
2342
2343unsafe fn integer_urem(
2345 _thread: &Thread,
2346 result: TValueCursor,
2347 arg0: TValue,
2348 nresults: i32,
2349 args: TValueCursor,
2350 nparams: i32,
2351) -> i32 {
2352 if nparams >= 2
2353 && nresults <= 1
2354 && arg0.is_integer()
2355 && unsafe { args.value_unchecked() }.is_integer()
2356 {
2357 let a = arg0.integer_value() as u64;
2358 let b = unsafe { args.value_unchecked() }.integer_value() as u64;
2359 if b == 0 {
2360 return -1;
2361 }
2362 unsafe { result.value_unchecked() }.set_integer((a % b) as i64);
2363 return 1;
2364 }
2365 -1
2366}
2367
2368unsafe fn integer_mod(
2370 _thread: &Thread,
2371 result: TValueCursor,
2372 arg0: TValue,
2373 nresults: i32,
2374 args: TValueCursor,
2375 nparams: i32,
2376) -> i32 {
2377 if nparams >= 2
2378 && nresults <= 1
2379 && arg0.is_integer()
2380 && unsafe { args.value_unchecked() }.is_integer()
2381 {
2382 let a = arg0.integer_value();
2383 let b = unsafe { args.value_unchecked() }.integer_value();
2384 if b == 0 {
2385 return -1;
2386 }
2387 if a == i64::MIN && b == -1 {
2388 unsafe { result.value_unchecked() }.set_integer(0);
2389 return 1;
2390 }
2391 let mut remainder = a % b;
2392 if remainder != 0 && ((a < 0) != (b < 0)) {
2393 remainder += b;
2394 }
2395 unsafe { result.value_unchecked() }.set_integer(remainder);
2396 return 1;
2397 }
2398 -1
2399}
2400
2401unsafe fn integer_clamp(
2403 _thread: &Thread,
2404 result: TValueCursor,
2405 arg0: TValue,
2406 nresults: i32,
2407 args: TValueCursor,
2408 nparams: i32,
2409) -> i32 {
2410 if nparams >= 3
2411 && nresults <= 1
2412 && arg0.is_integer()
2413 && unsafe { args.value_unchecked() }.is_integer()
2414 && unsafe { args.add(1).value_unchecked() }.is_integer()
2415 {
2416 let value = arg0.integer_value();
2417 let min = unsafe { args.value_unchecked() }.integer_value();
2418 let max = unsafe { args.add(1).value_unchecked() }.integer_value();
2419 if min > max {
2420 return -1;
2421 }
2422 unsafe { result.value_unchecked() }.set_integer(value.clamp(min, max));
2423 return 1;
2424 }
2425 -1
2426}
2427
2428unsafe fn integer_rotate_left(
2430 _thread: &Thread,
2431 result: TValueCursor,
2432 arg0: TValue,
2433 nresults: i32,
2434 args: TValueCursor,
2435 nparams: i32,
2436) -> i32 {
2437 if nparams >= 2
2438 && nresults <= 1
2439 && arg0.is_integer()
2440 && unsafe { args.value_unchecked() }.is_integer()
2441 {
2442 let value = arg0.integer_value() as u64;
2443 let shift = ((unsafe { args.value_unchecked() }.integer_value() as u64) % 64) as u32;
2444 let rotated = value.rotate_left(shift);
2445 unsafe { result.value_unchecked() }.set_integer(rotated as i64);
2446 return 1;
2447 }
2448 -1
2449}
2450
2451unsafe fn integer_r_rotate(
2453 _thread: &Thread,
2454 result: TValueCursor,
2455 arg0: TValue,
2456 nresults: i32,
2457 args: TValueCursor,
2458 nparams: i32,
2459) -> i32 {
2460 if nparams >= 2
2461 && nresults <= 1
2462 && arg0.is_integer()
2463 && unsafe { args.value_unchecked() }.is_integer()
2464 {
2465 let value = arg0.integer_value() as u64;
2466 let shift = ((unsafe { args.value_unchecked() }.integer_value() as u64) % 64) as u32;
2467 let rotated = value.rotate_right(shift);
2468 unsafe { result.value_unchecked() }.set_integer(rotated as i64);
2469 return 1;
2470 }
2471 -1
2472}
2473
2474unsafe fn integer_shift_left(
2476 _thread: &Thread,
2477 result: TValueCursor,
2478 arg0: TValue,
2479 nresults: i32,
2480 args: TValueCursor,
2481 nparams: i32,
2482) -> i32 {
2483 if nparams >= 2
2484 && nresults <= 1
2485 && arg0.is_integer()
2486 && unsafe { args.value_unchecked() }.is_integer()
2487 {
2488 let value = arg0.integer_value() as u64;
2489 let shift = unsafe { args.value_unchecked() }.integer_value();
2490 let shifted = if (-63..=63).contains(&shift) {
2491 if shift < 0 {
2492 value >> (-shift)
2493 } else {
2494 value << shift
2495 }
2496 } else {
2497 0
2498 };
2499 unsafe { result.value_unchecked() }.set_integer(shifted as i64);
2500 return 1;
2501 }
2502 -1
2503}
2504
2505unsafe fn integer_ar_shift(
2507 _thread: &Thread,
2508 result: TValueCursor,
2509 arg0: TValue,
2510 nresults: i32,
2511 args: TValueCursor,
2512 nparams: i32,
2513) -> i32 {
2514 if nparams >= 2
2515 && nresults <= 1
2516 && arg0.is_integer()
2517 && unsafe { args.value_unchecked() }.is_integer()
2518 {
2519 let value = arg0.integer_value();
2520 let shift = unsafe { args.value_unchecked() }.integer_value();
2521 let shifted = if (-63..=63).contains(&shift) {
2522 if shift < 0 {
2523 ((value as u64) << (-shift)) as i64
2524 } else {
2525 value >> shift
2526 }
2527 } else if shift < -63 {
2528 0
2529 } else if value < 0 {
2530 -1
2531 } else {
2532 0
2533 };
2534 unsafe { result.value_unchecked() }.set_integer(shifted);
2535 return 1;
2536 }
2537 -1
2538}
2539
2540unsafe fn integer_r_shift(
2542 _thread: &Thread,
2543 result: TValueCursor,
2544 arg0: TValue,
2545 nresults: i32,
2546 args: TValueCursor,
2547 nparams: i32,
2548) -> i32 {
2549 if nparams >= 2
2550 && nresults <= 1
2551 && arg0.is_integer()
2552 && unsafe { args.value_unchecked() }.is_integer()
2553 {
2554 let value = arg0.integer_value() as u64;
2555 let shift = unsafe { args.value_unchecked() }.integer_value();
2556 let shifted = if (-63..=63).contains(&shift) {
2557 if shift < 0 {
2558 value << (-shift)
2559 } else {
2560 value >> shift
2561 }
2562 } else {
2563 0
2564 };
2565 unsafe { result.value_unchecked() }.set_integer(shifted as i64);
2566 return 1;
2567 }
2568 -1
2569}
2570
2571unsafe fn integer_extract(
2573 _thread: &Thread,
2574 result: TValueCursor,
2575 arg0: TValue,
2576 nresults: i32,
2577 args: TValueCursor,
2578 nparams: i32,
2579) -> i32 {
2580 if nparams >= 3 && !unsafe { args.add(1).value_unchecked() }.is_integer() {
2581 return -1;
2582 }
2583 if nparams >= 2
2584 && nresults <= 1
2585 && arg0.is_integer()
2586 && unsafe { args.value_unchecked() }.is_integer()
2587 {
2588 let value = arg0.integer_value() as u64;
2589 let field = unsafe { args.value_unchecked() }.integer_value();
2590 let width = if nparams >= 3 {
2591 unsafe { args.add(1).value_unchecked() }.integer_value()
2592 } else {
2593 1
2594 };
2595 if !(0..=63).contains(&field) || !(1..=64).contains(&width) || field + width > 64 {
2596 return -1;
2597 }
2598 unsafe { result.value_unchecked() }
2599 .set_integer(((value >> field) & (u64::MAX >> (64 - width))) as i64);
2600 return 1;
2601 }
2602 -1
2603}
2604
2605unsafe fn integer_count_lz(
2607 _thread: &Thread,
2608 result: TValueCursor,
2609 arg0: TValue,
2610 nresults: i32,
2611 _args: TValueCursor,
2612 nparams: i32,
2613) -> i32 {
2614 if nparams >= 1 && nresults <= 1 && arg0.is_integer() {
2615 let value = arg0.integer_value() as u64;
2616 unsafe { result.value_unchecked() }.set_integer(if value == 0 {
2617 64
2618 } else {
2619 value.leading_zeros() as i64
2620 });
2621 return 1;
2622 }
2623 -1
2624}
2625
2626unsafe fn integer_count_rz(
2628 _thread: &Thread,
2629 result: TValueCursor,
2630 arg0: TValue,
2631 nresults: i32,
2632 _args: TValueCursor,
2633 nparams: i32,
2634) -> i32 {
2635 if nparams >= 1 && nresults <= 1 && arg0.is_integer() {
2636 let value = arg0.integer_value() as u64;
2637 unsafe { result.value_unchecked() }.set_integer(if value == 0 {
2638 64
2639 } else {
2640 value.trailing_zeros() as i64
2641 });
2642 return 1;
2643 }
2644 -1
2645}
2646
2647fn check_out_of_bounds(offset: i32, len: u32, access_size: usize) -> bool {
2650 (offset as u32 as u64) + (access_size as u64 - 1) >= len as u64
2651}
2652
2653unsafe fn read_buffer_data<T: Copy>(buffer: Buffer, offset: usize) -> T {
2654 let mut value = MaybeUninit::<T>::uninit();
2655 unsafe {
2656 ptr::copy_nonoverlapping(
2657 buffer.data_ptr().add(offset),
2658 value.as_mut_ptr().cast::<u8>(),
2659 core::mem::size_of::<T>(),
2660 );
2661 value.assume_init()
2662 }
2663}
2664
2665unsafe fn write_buffer_data<T: Copy>(buffer: Buffer, offset: usize, value: T) {
2666 unsafe {
2667 ptr::copy_nonoverlapping(
2668 (&raw const value).cast::<u8>(),
2669 buffer.data_mut_ptr().add(offset),
2670 core::mem::size_of::<T>(),
2671 );
2672 }
2673}
2674
2675#[cfg(not(target_endian = "big"))]
2676unsafe fn read_integer<T>(
2678 _thread: &Thread,
2679 result: TValueCursor,
2680 arg0: TValue,
2681 nresults: i32,
2682 args: TValueCursor,
2683 nparams: i32,
2684) -> i32
2685where
2686 T: Copy + Into<f64>,
2687{
2688 if nparams >= 2
2689 && nresults <= 1
2690 && arg0.is_buffer()
2691 && unsafe { args.value_unchecked() }.is_number()
2692 {
2693 let offset = unsafe { args.value_unchecked() }.number_value() as i32;
2694 let buffer = arg0.buffer_value();
2695 if check_out_of_bounds(
2696 offset,
2697 unsafe { buffer.as_ptr().as_ref().unwrap_unchecked().len },
2698 std::mem::size_of::<T>(),
2699 ) {
2700 return -1;
2701 }
2702
2703 let value = unsafe { read_buffer_data::<T>(buffer, offset as usize) };
2704 unsafe { result.value_unchecked() }.set_number(value.into());
2705 return 1;
2706 }
2707
2708 -1
2709}
2710
2711#[cfg(target_endian = "big")]
2712unsafe fn read_integer<T>(
2714 _thread: &Thread,
2715 _result: TValueCursor,
2716 _arg0: TValue,
2717 _nresults: i32,
2718 _args: TValueCursor,
2719 _nparams: i32,
2720) -> i32
2721where
2722 T: Copy + Into<f64>,
2723{
2724 -1
2725}
2726
2727#[cfg(not(target_endian = "big"))]
2728unsafe fn write_unsigned<T>(
2730 _thread: &Thread,
2731 _result: TValueCursor,
2732 arg0: TValue,
2733 nresults: i32,
2734 args: TValueCursor,
2735 nparams: i32,
2736) -> i32
2737where
2738 T: Copy,
2739{
2740 if nparams >= 3
2741 && nresults <= 0
2742 && arg0.is_buffer()
2743 && unsafe { args.value_unchecked() }.is_number()
2744 && unsafe { args.add(1).value_unchecked().is_number() }
2745 {
2746 let offset = unsafe { args.value_unchecked() }.number_value() as i32;
2747 let buffer = arg0.buffer_value();
2748 if check_out_of_bounds(
2749 offset,
2750 unsafe { buffer.as_ptr().as_ref().unwrap_unchecked().len },
2751 std::mem::size_of::<T>(),
2752 ) {
2753 return -1;
2754 }
2755
2756 let value =
2757 ((unsafe { args.add(1).value_unchecked().number_value() } as i64) as u32).to_le_bytes();
2758 unsafe {
2759 ptr::copy_nonoverlapping(
2760 value.as_ptr(),
2761 buffer.data_mut_ptr().add(offset as usize),
2762 std::mem::size_of::<T>(),
2763 );
2764 }
2765 return 0;
2766 }
2767
2768 -1
2769}
2770
2771#[cfg(target_endian = "big")]
2772unsafe fn write_unsigned<T>(
2774 _thread: &Thread,
2775 _result: TValueCursor,
2776 _arg0: TValue,
2777 _nresults: i32,
2778 _args: TValueCursor,
2779 _nparams: i32,
2780) -> i32
2781where
2782 T: Copy,
2783{
2784 -1
2785}
2786
2787#[cfg(not(target_endian = "big"))]
2788unsafe fn read_fp<T>(
2790 _thread: &Thread,
2791 result: TValueCursor,
2792 arg0: TValue,
2793 nresults: i32,
2794 args: TValueCursor,
2795 nparams: i32,
2796) -> i32
2797where
2798 T: Copy,
2799{
2800 if nparams >= 2
2801 && nresults <= 1
2802 && arg0.is_buffer()
2803 && unsafe { args.value_unchecked() }.is_number()
2804 {
2805 let offset = unsafe { args.value_unchecked() }.number_value() as i32;
2806 let buffer = arg0.buffer_value();
2807 if check_out_of_bounds(
2808 offset,
2809 unsafe { buffer.as_ptr().as_ref().unwrap_unchecked().len },
2810 std::mem::size_of::<T>(),
2811 ) {
2812 return -1;
2813 }
2814
2815 match std::mem::size_of::<T>() {
2816 4 => {
2817 let value = unsafe { read_buffer_data::<f32>(buffer, offset as usize) };
2818 unsafe { result.value_unchecked() }.set_number(f64::from(value));
2819 }
2820 8 => {
2821 let value = unsafe { read_buffer_data::<f64>(buffer, offset as usize) };
2822 unsafe { result.value_unchecked() }.set_number(value);
2823 }
2824 _ => unreachable!(),
2825 }
2826
2827 return 1;
2828 }
2829
2830 -1
2831}
2832
2833#[cfg(target_endian = "big")]
2834unsafe fn read_fp<T>(
2836 _thread: &Thread,
2837 _result: TValueCursor,
2838 _arg0: TValue,
2839 _nresults: i32,
2840 _args: TValueCursor,
2841 _nparams: i32,
2842) -> i32
2843where
2844 T: Copy,
2845{
2846 -1
2847}
2848
2849#[cfg(not(target_endian = "big"))]
2850unsafe fn write_fp<T>(
2852 _thread: &Thread,
2853 _result: TValueCursor,
2854 arg0: TValue,
2855 nresults: i32,
2856 args: TValueCursor,
2857 nparams: i32,
2858) -> i32
2859where
2860 T: Copy,
2861{
2862 if nparams >= 3
2863 && nresults <= 0
2864 && arg0.is_buffer()
2865 && unsafe { args.value_unchecked() }.is_number()
2866 && unsafe { args.add(1).value_unchecked().is_number() }
2867 {
2868 let offset = unsafe { args.value_unchecked() }.number_value() as i32;
2869 let buffer = arg0.buffer_value();
2870 if check_out_of_bounds(
2871 offset,
2872 unsafe { buffer.as_ptr().as_ref().unwrap_unchecked().len },
2873 std::mem::size_of::<T>(),
2874 ) {
2875 return -1;
2876 }
2877
2878 match std::mem::size_of::<T>() {
2879 4 => {
2880 let value = unsafe { args.add(1).value_unchecked().number_value() } as f32;
2881 unsafe { write_buffer_data::<f32>(buffer, offset as usize, value) };
2882 }
2883 8 => {
2884 let value = unsafe { args.add(1).value_unchecked().number_value() };
2885 unsafe { write_buffer_data::<f64>(buffer, offset as usize, value) };
2886 }
2887 _ => unreachable!(),
2888 }
2889
2890 return 0;
2891 }
2892
2893 -1
2894}
2895
2896#[cfg(target_endian = "big")]
2897unsafe fn write_fp<T>(
2899 _thread: &Thread,
2900 _result: TValueCursor,
2901 _arg0: TValue,
2902 _nresults: i32,
2903 _args: TValueCursor,
2904 _nparams: i32,
2905) -> i32
2906where
2907 T: Copy,
2908{
2909 -1
2910}
2911
2912#[cfg(not(target_endian = "big"))]
2913unsafe fn buffer_read_long(
2915 _thread: &Thread,
2916 result: TValueCursor,
2917 arg0: TValue,
2918 nresults: i32,
2919 args: TValueCursor,
2920 nparams: i32,
2921) -> i32 {
2922 if nparams >= 2
2923 && nresults <= 1
2924 && arg0.is_buffer()
2925 && unsafe { args.value_unchecked() }.is_number()
2926 {
2927 let offset = unsafe { args.value_unchecked() }.number_value() as i32;
2928 let buffer = arg0.buffer_value();
2929 if check_out_of_bounds(
2930 offset,
2931 unsafe { buffer.as_ptr().as_ref().unwrap_unchecked().len },
2932 std::mem::size_of::<i64>(),
2933 ) {
2934 return -1;
2935 }
2936
2937 let value = unsafe { read_buffer_data::<i64>(buffer, offset as usize) };
2938 unsafe { result.value_unchecked() }.set_integer(value);
2939 return 1;
2940 }
2941
2942 -1
2943}
2944
2945#[cfg(target_endian = "big")]
2946unsafe fn buffer_read_long(
2948 _thread: &Thread,
2949 _result: TValueCursor,
2950 _arg0: TValue,
2951 _nresults: i32,
2952 _args: TValueCursor,
2953 _nparams: i32,
2954) -> i32 {
2955 -1
2956}
2957
2958#[cfg(not(target_endian = "big"))]
2959unsafe fn buffer_write_long(
2961 _thread: &Thread,
2962 _result: TValueCursor,
2963 arg0: TValue,
2964 nresults: i32,
2965 args: TValueCursor,
2966 nparams: i32,
2967) -> i32 {
2968 if nparams >= 3
2969 && nresults <= 0
2970 && arg0.is_buffer()
2971 && unsafe { args.value_unchecked() }.is_number()
2972 {
2973 unsafe {
2974 if !args.add(1).value_unchecked().is_integer() {
2975 return -1;
2976 }
2977
2978 let offset = args.value_unchecked().number_value() as i32;
2979 let buffer = arg0.buffer_value();
2980 if check_out_of_bounds(
2981 offset,
2982 buffer.as_ptr().as_ref().unwrap_unchecked().len,
2983 std::mem::size_of::<i64>(),
2984 ) {
2985 return -1;
2986 }
2987
2988 write_buffer_data::<i64>(
2989 buffer,
2990 offset as usize,
2991 args.add(1).value_unchecked().integer_value(),
2992 );
2993 return 0;
2994 }
2995 }
2996
2997 -1
2998}
2999
3000#[cfg(target_endian = "big")]
3001unsafe fn buffer_write_long(
3003 _thread: &Thread,
3004 _result: TValueCursor,
3005 _arg0: TValue,
3006 _nresults: i32,
3007 _args: TValueCursor,
3008 _nparams: i32,
3009) -> i32 {
3010 -1
3011}
3012
3013pub static LUAU_F_TABLE: [LuauFastFunction; 256] = [
3015 missing,
3016 assert,
3017 abs,
3018 acos,
3019 asin,
3020 atan2,
3021 atan,
3022 ceil,
3023 cosh,
3024 cos,
3025 deg,
3026 exp,
3027 floor,
3028 fmod,
3029 frexp,
3030 ldexp,
3031 log10,
3032 log,
3033 max,
3034 min,
3035 modf,
3036 pow,
3037 rad,
3038 sinh,
3039 sin,
3040 sqrt,
3041 tanh,
3042 tan,
3043 ar_shift,
3044 band,
3045 bnot,
3046 bor,
3047 bxor,
3048 btest,
3049 extract,
3050 rotate_left,
3051 shift_left,
3052 replace,
3053 r_rotate,
3054 r_shift,
3055 type_,
3056 byte,
3057 char,
3058 len,
3059 type_of,
3060 sub,
3061 clamp,
3062 sign,
3063 round,
3064 raw_set,
3065 raw_get,
3066 raw_equal,
3067 t_insert,
3068 t_unpack,
3069 vector,
3070 count_lz,
3071 count_rz,
3072 select,
3073 raw_len,
3074 extract_k,
3075 get_metatable,
3076 set_metatable,
3077 to_number,
3078 to_string,
3079 byte_swap,
3080 read_integer::<i8>,
3081 read_integer::<u8>,
3082 write_unsigned::<u8>,
3083 read_integer::<i16>,
3084 read_integer::<u16>,
3085 write_unsigned::<u16>,
3086 read_integer::<i32>,
3087 read_integer::<u32>,
3088 write_unsigned::<u32>,
3089 read_fp::<f32>,
3090 write_fp::<f32>,
3091 read_fp::<f64>,
3092 write_fp::<f64>,
3093 vector_magnitude,
3094 vector_normalize,
3095 vector_cross,
3096 vector_dot,
3097 vector_floor,
3098 vector_ceil,
3099 vector_abs,
3100 vector_sign,
3101 vector_clamp,
3102 vector_min,
3103 vector_max,
3104 lerp,
3105 vector_lerp,
3106 is_nan,
3107 is_inf,
3108 is_finite,
3109 integer_create,
3110 integer_to_number,
3111 integer_neg,
3112 integer_add,
3113 integer_sub,
3114 integer_mul,
3115 integer_div,
3116 integer_min,
3117 integer_max,
3118 integer_rem,
3119 integer_idiv,
3120 integer_udiv,
3121 integer_urem,
3122 integer_mod,
3123 integer_clamp,
3124 integer_band,
3125 integer_bor,
3126 integer_bnot,
3127 integer_bxor,
3128 integer_lt,
3129 integer_le,
3130 integer_ult,
3131 integer_ule,
3132 integer_gt,
3133 integer_ge,
3134 integer_ugt,
3135 integer_uge,
3136 integer_shift_left,
3137 integer_r_shift,
3138 integer_ar_shift,
3139 integer_rotate_left,
3140 integer_r_rotate,
3141 integer_extract,
3142 integer_btest,
3143 integer_count_rz,
3144 integer_count_lz,
3145 integer_byte_swap,
3146 buffer_read_long,
3147 buffer_write_long,
3148 missing,
3149 missing,
3150 missing,
3151 missing,
3152 missing,
3153 missing,
3154 missing,
3155 missing,
3156 missing,
3157 missing,
3158 missing,
3159 missing,
3160 missing,
3161 missing,
3162 missing,
3163 missing,
3164 missing,
3165 missing,
3166 missing,
3167 missing,
3168 missing,
3169 missing,
3170 missing,
3171 missing,
3172 missing,
3173 missing,
3174 missing,
3175 missing,
3176 missing,
3177 missing,
3178 missing,
3179 missing,
3180 missing,
3181 missing,
3182 missing,
3183 missing,
3184 missing,
3185 missing,
3186 missing,
3187 missing,
3188 missing,
3189 missing,
3190 missing,
3191 missing,
3192 missing,
3193 missing,
3194 missing,
3195 missing,
3196 missing,
3197 missing,
3198 missing,
3199 missing,
3200 missing,
3201 missing,
3202 missing,
3203 missing,
3204 missing,
3205 missing,
3206 missing,
3207 missing,
3208 missing,
3209 missing,
3210 missing,
3211 missing,
3212 missing,
3213 missing,
3214 missing,
3215 missing,
3216 missing,
3217 missing,
3218 missing,
3219 missing,
3220 missing,
3221 missing,
3222 missing,
3223 missing,
3224 missing,
3225 missing,
3226 missing,
3227 missing,
3228 missing,
3229 missing,
3230 missing,
3231 missing,
3232 missing,
3233 missing,
3234 missing,
3235 missing,
3236 missing,
3237 missing,
3238 missing,
3239 missing,
3240 missing,
3241 missing,
3242 missing,
3243 missing,
3244 missing,
3245 missing,
3246 missing,
3247 missing,
3248 missing,
3249 missing,
3250 missing,
3251 missing,
3252 missing,
3253 missing,
3254 missing,
3255 missing,
3256 missing,
3257 missing,
3258 missing,
3259 missing,
3260 missing,
3261 missing,
3262 missing,
3263 missing,
3264 missing,
3265 missing,
3266 missing,
3267 missing,
3268 missing,
3269 missing,
3270 missing,
3271];